Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Swift, how do I have a UIScrollView subclass that has an internal and external delegate?

I'm subclassing UIScrollView to add some features such as double tap to zoom and an image property for gallery purposes. But in order to do the image part my subclass has to be its own delegate and implement the viewForZoomingInScrollView.

But then when someone uses my scroll view subclass, they might like to get delegate notifications as well to see scrollViewDidScroll or what have you.

In Swift, how do I get both of these?

like image 413
Doug Smith Avatar asked Nov 16 '14 03:11

Doug Smith


1 Answers

Here is a Swift version of this pattern:

Although forwardInvocation: is disabled in Swift, we can still use forwardingTargetForSelector:

class MyScrollView: UIScrollView {

    class _DelegateProxy: NSObject, UIScrollViewDelegate {
        weak var _userDelegate: UIScrollViewDelegate?

        override func respondsToSelector(aSelector: Selector) -> Bool {
            return super.respondsToSelector(aSelector) || _userDelegate?.respondsToSelector(aSelector) == true
        }

        override func forwardingTargetForSelector(aSelector: Selector) -> AnyObject? {
            if _userDelegate?.respondsToSelector(aSelector) == true {
                return _userDelegate
            }
            else {
                return super.forwardingTargetForSelector(aSelector)
            }
        }

        func viewForZoomingInScrollView(scrollView: MyScrollView) -> UIView? {
            return scrollView.viewForZooming()
        }

        // Just a demo. You don't need this.
        func scrollViewDidScroll(scrollView: MyScrollView) {
            scrollView.didScroll()
            _userDelegate?.scrollViewDidScroll?(scrollView)
        }
    }

    private var _delegateProxy =  _DelegateProxy()

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        super.delegate = _delegateProxy
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        super.delegate = _delegateProxy
    }

    override var delegate:UIScrollViewDelegate? {
        get {
            return _delegateProxy._userDelegate
        }
        set {
            self._delegateProxy._userDelegate = newValue;
            /* It seems, we don't need this anymore.
            super.delegate = nil
            super.delegate = _delegateProxy
            */
        }
    }

    func viewForZooming() -> UIView? {
        println("self viewForZooming")
        return self.subviews.first as? UIView // whatever
    }

    func didScroll() {
        println("self didScroll")
    }
}
like image 193
rintaro Avatar answered Sep 30 '22 20:09

rintaro