在Swift中,我如何拥有一个具有内部和外部委托的UIScrollView子类?

Dou*_*ith 12 delegates uiscrollview swift

我正在进行子类化UIScrollView以添加一些功能,例如双击缩放和用于图库目的的图像属性.但是为了做图像部分我的子类必须是它自己的委托并实现viewForZoomingInScrollView.

但是当有人使用我的滚动视图子类时,他们可能也希望获得委托通知以查看scrollViewDidScroll或者您有什么.

在Swift中,我如何获得这两个?

rin*_*aro 19

这是这种模式的Swift版本:

虽然forwardInvocation:在Swift中被禁用,但我们仍然可以使用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")
    }
}
Run Code Online (Sandbox Code Playgroud)


Tam*_*gel 7

Swift 4+ 版本的rintaro 的优秀答案

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

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

        override func forwardingTarget(for aSelector: Selector!) -> Any? {
            if _userDelegate?.responds(to: aSelector) == true {
                return _userDelegate
            }

            return super.forwardingTarget(for: aSelector)
        }

        //This function is just a demonstration, it can be replaced/removed.
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            (scrollView as? MyScrollView)?.didScroll()

            _userDelegate?.scrollViewDidScroll?(scrollView)
        }
    }

    fileprivate let _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 {
            _delegateProxy._userDelegate = newValue
        }
    }

    func didScroll() {
        print("didScroll")
    }
}
Run Code Online (Sandbox Code Playgroud)