1

I have a ProfileVC that contain a list. I can click on any of the row cell will show peek and pop feature.

ProfileVC.swift

I added the extention

extension ProfileViewController : UIViewControllerPreviewingDelegate {
    
    func detailViewController(for indexPath: IndexPath) -> ProfileDetailViewController {
        guard let vc = storyboard?.instantiateViewController(withIdentifier: "ProfileDetailViewController") as? ProfileDetailViewController else {
            fatalError("Couldn't load detail view controller")
        }
        
        let cell = profileTableView.cellForRow(at: indexPath) as! ProfileTableViewCell
        
        // Pass over a reference to the next VC
        vc.title   = cell.profileName?.text
        vc.cpe     = loginAccount.cpe
        vc.profile = loginAccount.cpeProfiles[indexPath.row - 1]
        
        consoleLog(indexPath.row - 1)
        
        //print("3D Touch Detected !!!",vc)
        
        return vc
    }
    
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        if let indexPath = profileTableView.indexPathForRow(at: location) {
            
            // Enable blurring of other UI elements, and a zoom in animation while peeking.
            previewingContext.sourceRect = profileTableView.rectForRow(at: indexPath)
            
            return detailViewController(for: indexPath)
        }
        
        return nil
    }
    
    //ViewControllerToCommit
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        
        // Push the configured view controller onto the navigation stack.
        navigationController?.pushViewController(viewControllerToCommit, animated: true)
    }
    
}

Then, in the same file ProfileVC.swift in viewDidLoad() I registered it

if (self.traitCollection.forceTouchCapability == .available){
    print("-------->", "Force Touch is Available")
    registerForPreviewing(with: self, sourceView: view)
}
else{
    print("-------->", "Force Touch is NOT Available")
}

Result

I have no idea why I can not click on the 4th cell.

The last cell of the row does not trigger Peek & Pop.

How would one go about and debug this further?

Community
  • 1
  • 1
code-8
  • 54,650
  • 106
  • 352
  • 604
  • What does the debugger show? Is the delegate function called but the `if let` fails, or is the function not called? – Paulw11 Jan 18 '19 at 20:20
  • Which function you referring to? Also, do I need to add anything in my `ProfileDetailVC.swift` ? – code-8 Jan 18 '19 at 20:29
  • If you add more cells does it still fail only on the last one? – Galo Torres Sevilla Jan 18 '19 at 20:30
  • @GaloTorresSevilla : I can add one more profile, and find out. Let me do it now. – code-8 Jan 18 '19 at 20:30
  • I mean the `previewingContext(_,location:)` function. – Paulw11 Jan 18 '19 at 20:43
  • @Paulw11 Let me do a print statement in there, and see if it got printed. – code-8 Jan 18 '19 at 21:30
  • @GaloTorresSevilla : Yes, I can reproduce it, add nother profile, only the bottom one is not triggeting Peek & Pop. – code-8 Jan 18 '19 at 21:32
  • Or set a breakpoint and use the debugger. If you don't know how to use the debugger in Xcode, now is the time to learn. It is an enormously powerful tool. – Paulw11 Jan 18 '19 at 21:33
  • @Paulw11 : I added a print `print("_ previewingContext location")` I got it to print : https://i.imgur.com/P2oIWyl.png – code-8 Jan 18 '19 at 21:40
  • My print statement inside `if let indexPath` never get executed only for that last cell. https://i.imgur.com/c0Okks5.png – code-8 Jan 18 '19 at 21:43
  • Right, so the most likely conclusion is that the `if let` is falling through (again, the debugger would show you this straight away!). What source view do you use when you call `registerForPreviewing` ? – Paulw11 Jan 18 '19 at 21:45
  • @Paulw11 I called `registerForPreviewing` in same **ProfileVC** inside `viewDidLoad()` – code-8 Jan 18 '19 at 21:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/186943/discussion-between-paulw11-and-kyo). – Paulw11 Jan 18 '19 at 21:47
  • When registering for previewing you should pass your tableview as the source view instead of the view controller's view – dan Jan 18 '19 at 22:14
  • @dan : Can you please answer your suggestion so I can try ? I'm still new on iOS. – code-8 Jan 18 '19 at 23:06

1 Answers1

1

You are registering your view controller's root view as the source view for the peek context. As a result, the CGPoint that is passed to previewingContext(_ viewControllerForLocation:)` is in the coordinate space of that view.

When you try and retrieve the corresponding row from your table view the point will actually be offset from the corresponding point in the table view's frame based on the relative position of the table view in the root view.

This offset means that a corresponding row can’t be retrieved for the last row in the table; indexPathForRow(at:) returns nil and your function returns without doing anything.

You might also find that if you force touch towards the bottom of a cell you actually get a peek for the next row.

You could translate the CGPoint into the table view’s frame, but it is simpler to just specify your tableview as the source view when you register for previewing:

if (self.traitCollection.forceTouchCapability == .available){
    print("-------->", "Force Touch is Available")
    registerForPreviewing(with: self, sourceView: self.profileTableView)
}
else{
    print("-------->", "Force Touch is NOT Available")
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186