Skip to content

Instantly share code, notes, and snippets.

@ULazdins
Created December 5, 2019 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ULazdins/71a2bfd474c7f6fe9d0e61a749271247 to your computer and use it in GitHub Desktop.
Save ULazdins/71a2bfd474c7f6fe9d0e61a749271247 to your computer and use it in GitHub Desktop.
A way to use separate delegates for UIScrollViewDelegate and UITableViewDelegate when using UITableView. Inspired by https://gist.github.com/cdzombak/4454286
public class TableViewSplitDelegate: NSObject, UITableViewDelegate {
weak var scrollViewDelegate: UIScrollViewDelegate?
weak var tableViewDelegate: UITableViewDelegate?
override public func forwardingTarget(for aSelector: Selector!) -> Any? {
if selectorIsPartOfUIScrollViewDelegate(selector: aSelector) {
return scrollViewDelegate
}
if selectorIsPartOfUITableViewDelegate(selector: aSelector) {
return tableViewDelegate
}
return nil
}
override public func responds(to aSelector: Selector) -> Bool {
guard let target = forwardingTarget(for: aSelector) as AnyObject? else {
return super.responds(to: aSelector)
}
if target === scrollViewDelegate {
return target.responds(to: aSelector)
} else if target === tableViewDelegate {
return target.responds(to: aSelector)
} else {
return super.responds(to: aSelector)
}
}
// MARK: - Private
private func isInstanceMethodForProtocol(selector: Selector, `protocol`: Protocol, isRequired: Bool) -> Bool {
let methodDesc = protocol_getMethodDescription(`protocol`, selector, isRequired, true)
return methodDesc.name != nil
}
private func isInstanceMethodForProtocol(selector: Selector, `protocol`: Protocol) -> Bool {
return isInstanceMethodForProtocol(selector: selector, protocol: `protocol`, isRequired: true) ||
isInstanceMethodForProtocol(selector: selector, protocol: `protocol`, isRequired: false)
}
private func selectorIsPartOfUIScrollViewDelegate(selector aSelector: Selector) -> Bool {
// assuming all UIScrollViewDelegate methods are instance methods
return isInstanceMethodForProtocol(selector: aSelector, protocol: UIScrollViewDelegate.self)
}
private func selectorIsPartOfUITableViewDelegate(selector aSelector: Selector) -> Bool {
// assuming all UIScrollViewDelegate methods are instance methods
return isInstanceMethodForProtocol(selector: aSelector, protocol: UITableViewDelegate.self)
}
}
@ULazdins
Copy link
Author

ULazdins commented Dec 5, 2019

Usage can be different, but I chose to subclass UITableView and handle both delegates there:

public class SplitDelegateUITableView: UITableView {
    // We need to keep strong reference to `TableViewSplitDelegate` otherwise it will be deallocated immediately
    // swiftlint:disable:next weak_delegate
    public var splitDelegate = TableViewSplitDelegate()
    
    public weak var scrollViewDelegate: UIScrollViewDelegate? {
        didSet {
            splitDelegate.scrollViewDelegate = scrollViewDelegate
        }
    }
    
    override public var delegate: UITableViewDelegate? {
        didSet {
            if delegate is TableViewSplitDelegate { return } // Prefent loops
            
            splitDelegate.tableViewDelegate = delegate
            self.delegate = splitDelegate
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment