Overriding delegate property of UIScrollView in Swift (like UICollectionView does)

后端 未结 6 2082
春和景丽
春和景丽 2021-02-01 02:36

UIScrollView has a delegate property which conforms to UIScrollViewDelegate

protocol UIScrollViewDelegate : NSObjectProtocol {
    //...
}
class UIScrollView : U         


        
相关标签:
6条回答
  • 2021-02-01 02:47

    You can override get and set method by declare function like:

    func setDelegate(delegate:UITableViewDelegate?){
         self.delegateInterceptor = delegate;
    }
    

    swift compiler the property to method as Objective-c does.

    0 讨论(0)
  • 2021-02-01 02:48

    My favoured method personally is not to subclass scrollviews directly but to make a UIView subclass containing and acting as delegate for a separate scrollview, then forward that scrollview's delegate messages on to the UIView subclass's own delegate where necessary. This also allows for the adding of custom controls outside of the area defined by the scroll view. It may seem a little inelegant compared to a direct subclass, but it does at least avoid unpleasant hacks.

    0 讨论(0)
  • 2021-02-01 02:49

    Consider the following situation:

    class BaseProp {}
    
    class Base {
        var prop: BaseProp
    }
    

    Then if you do this:

    class DerivedProp: BaseProp {}
    
    class Derived: Base {
        override var prop: DerivedProp
    }
    

    Then if would break the subclassing principles (namely, the Liskov Substitution Principle). Basically what you are doing is limiting the scope of "var prop" from wider "BaseProp" type to a more narrow "DerivedProp" type. Then this kind of code would be possible, which does not make sense:

    class UnrelatedProp: BaseProp {}
    
    let derived = Derived()
    let base = derived as Base
    base.prop = UnrelatedProp()
    

    Note that we are assigning an instance of UnrelatedProp to the property, which does not make sense for the Derived instance which we actually operate with. ObjectiveC allows such kind of ambiguity, but Swift doesn't.

    0 讨论(0)
  • 2021-02-01 02:51

    You can do like this:

    protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
        func someNewFunction()
    }
    
    class CustomScrollView: UIScrollView {
    
        weak var myDelegate: ExtendedScrollViewDelegate?
        override weak var delegate: UIScrollViewDelegate? {
            didSet {
                myDelegate = delegate as? ExtendedScrollViewDelegate
            }
        }
    }
    

    Hope this helps

    0 讨论(0)
  • 2021-02-01 02:55

    I think overriding an inherited property is something that's possible in Objective-C but not (at least currently) in Swift. The way I've handled this is to declare a separate delegate as a computed property of the correct type that gets and sets the actual delegate:

    @objc protocol MyScrollViewDelegate : UIScrollViewDelegate, NSObjectProtocol {
        func myHeight() -> CGFloat
        // ...
    }
    
    class MyScrollView: UIScrollView {
        var myDelegate: MyScrollViewDelegate? {
            get { return self.delegate as? MyScrollViewDelegate }
            set { self.delegate = newValue }
        }
    }
    

    This way anything that calls the scroll view delegate normally still works, and you can call your particular delegate methods on self.myDelegate, like this:

    if let height = self.myDelegate?.myHeight() {
        // ...
    }
    
    0 讨论(0)
  • 2021-02-01 03:03

    Here is a solution for changing the type of the overriding properties in Swift. It is especially useful when you need to extend protocols of delegates.

    @objc protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
         func someNewFunction()
    }
    
    class CustomScrollView: UIScrollView {
    
        weak var delegateInterceptor: ExtendedScrollViewDelegate?
        override var delegate: UIScrollViewDelegate! {
            didSet {
                if let newValue = delegate {
                    let castedDelegate = unsafeBitCast(delegate, ExtendedScrollViewDelegate.self)
                    delegateInterceptor = castedDelegate
                }
                else {
                    delegateInterceptor = nil
                }
            }
        }
    }
    

    This works as tested with Swift version 1.2. I hope it helps.

    0 讨论(0)
提交回复
热议问题