swiftmacosdelegatesmacos-sierranscollectionview

swift macOS - Custom NSCollectionViewDelegate doesn't get called


I made an extension for the NSCollectionViewDelegate, in which I declared two new functions for handling clicking on NSCollectionViewItems. I call the delegate methods from a custom NSCollectionViewItems subclass and set the collectionView's delegate to self in my ViewController. However the new functions are called in the NSCollectionViewDelegate, but not in my ViewController.

My NSCollectionViewDelegate extension:

extension NSCollectionViewDelegate {

    func collectionView(_ collectionView: NSCollectionView, didDoubleClickOnItem item: Int) {
        print("didDoubleClickOnItem delegate")
    }

    func collectionView(_ collectionView: NSCollectionView, didRightClickOnItem item: Int) {
        print("didRightClickOnItem delegate")
    }
}

These functions are called in my NSCollectionViewItem subclass with:

self.collectionView.delegate?.collectionView(self.collectionView, didDoubleClickOnItem: itemIndex)

But the implemented function in my ViewController

func collectionView(_ collectionView: NSCollectionView, didDoubleClickOnItem item: Int) {
    
    print("didDoubleClickOnItem")
}

doesn't get called.

What am I doing wrong?

Thanks in advance


Solution

  • Like @AMAN77 said, you have extended the basic delegate functionalities of NSCollectionViewDelegate with some new (and already implemented) functionality, so the compiler sees no harm in that.

    There's no rule that forces you to use only one delegate. If you would like your ViewController to be called, as delegate on behalf of NSCollectionViewItems, do the following.

    Create a protocol that serves your needs; what would someone tell your delegate?

    Probably the following:

    protocol NSCollectionViewClickHandler {
        func collectionView(_ collectionView: NSCollectionView, didDoubleClickOnItem item: Int)
        func collectionView(_ collectionView: NSCollectionView, didRightClickOnItem item: Int)
    }
    

    So, since you want ViewController to act as a delegate, it should implement these functions. (You already did that for at least didDoubleClickOnItem)

    imho It looks neat if you would do that in an extension of your ViewController

    class ViewController {
       // All the regular stuff goes in here
       // …
       override func viewDidLoad() {
          super.viewDidLoad()
          // set self as (NSCollectionViewClickHandler) delegate of some object
       }
    
    }
    
    extension ViewController: NSCollectionViewDelegate {
        // implement those function of NSCollectionViewDelegate that you'd like to use, 
        // and the ones that are required.
    }
    
    extension ViewController: NSCollectionViewClickHandler {
       func collectionView(_ collectionView: NSCollectionView, didDoubleClickOnItem item: Int) {
          print("didDoubleClickOnItem")
       }
    
       func collectionView(_ collectionView: NSCollectionView, didRightClickOnItem item: Int) {
          print("didDoubleClickOnItem")
       }
    
       // If you need other methods to properly implement your delegate methods,
       // you can group them in this extension as well: they logically belong together.
       // …
    }
    
    
    class YourSubclassOfNSCollectionViewItems: NSCollectionViewItems {
       var clickDelegate: NSCollectionViewClickHandler?
    
       func someFunction() {
          // does something, and gets the itemIndex
          clickDelegate?.collectionView(self.collectionView, didDoubleClickOnItem: itemIndex)
       }
    
    }
    

    I hope you now have a better understanding of how to use proto-…uh I mean delegates ;-) Good luck! (Bonus tip: here is a quick-and-easy intro to learn more about delegates and other design patterns)