swiftuitableviewuicollectionviewuitableviewsectionheaderuicollectionviewdelegate

Pros/cons of implementing a particular set of delegate methods versus not implementing them and the effects of implementing one but not another?


In regards to UITableView & UICollectionView & their respective protocols, UITableViewDataSource & UITableViewDelegate + UICollectionViewDelegate & UICollectionViewDataSource -- are there any pros and cons to implementing one method, but not the other or a particular set of methods and not the rest of the methods or a unique combination of specific methods?

For example, if I am to implement heightForFooter but not viewForFooter - what happens or can happen? Does this negative impact performance or the scroll of the table view?

Is there a guide which shows that which if any methods are implemented, others should be combined and dually implemented alongside them?


Solution

  • Re: correctness

    Is there a guide which shows that which if any methods are implemented, others should be combined and dually implemented alongside them?

    Not from what I've seen, though sometimes the documentation mentions it. E.g. from the docs of NSTableViewDataSource:

    If you’re not using Cocoa bindings to provide data to the table view, the following methods are required:

    • numberOfRows(in:)
    • tableView(_:objectValueFor:row:)
    • tableView(_:setObjectValue:for:row:) (cell-based tables only)

    In general, if a method is optional, but required from the context, then there will be a runtime error telling you to implment it, e.g.:

    Illegal NSTableView data source (Foo). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:

    Either that, or stuff will silently fail (e.g. if you don't implement NSTableViewDelegate.tableView(_:viewFor:row:), no drawing will happen, and all your cells will just be blank views.

    Re: performance

    There shouldn't be any real performance difference with not implementing optional methods.

    Each of these methods is likely called as if you had this in Swift (most of these frameworks are still implemented in Objective C):

    let result: Result? = yourTarget.someMethod?(someArg)
    

    which is really just shorthand for:

    let result: Result? = yourTarget.responds(to: #selector(YourTargetsClass.someMethod))
        ? target.method(someArg)
        : nil
    

    That is, it's one dynamic method lookup to check if your object responds to the message, and one dynamic message send to actually invoke the method (for the case where it does respond).

    There's a teeny tiny optimization that one could squeeze out here: if your method implementation is empty, then you're better off not having it at all. That will prevent a needless message send. Though it's obviously not something to worry about until you're sure it's a hotspot in a profiler.

    Of course, nothing stops a library author from writing:

    if yourObject.responds(to: #selector(someMessage)) {
        doSomethingVeryExpensiveForNoGoodReason()
    }
    

    ... but that's unlikely.