在Swift中覆盖UIScrollView的委托属性(比如UICollectionView)

时间:2014-09-08 12:50:52

标签: ios swift uiscrollview uiscrollviewdelegate

UIScrollView有一个委托属性,符合UIScrollViewDelegate

protocol UIScrollViewDelegate : NSObjectProtocol {
    //...
}
class UIScrollView : UIView, NSCoding {
    unowned(unsafe) var delegate: UIScrollViewDelegate?
    //...
}

UICollectionView使用不同的类型UICollectionViewDelegate

覆盖此属性
protocol UICollectionViewDelegate : UIScrollViewDelegate, NSObjectProtocol {
   //...
}

class UICollectionView : UIScrollView {
     unowned(unsafe) var delegate: UICollectionViewDelegate?
   //...
}

当我尝试使用我的协议覆盖UIScrollViews委托时,如下所示:

protocol MyScrollViewDelegate : UIScrollViewDelegate, NSObjectProtocol {
    //...
}

class MyScrollView: UIScrollView {
    unowned(unsafe) var delegate: MyScrollViewDelegate?

}

编译器给了我两个警告:

  • 财产'代表'使用类型' MyScrollViewDelegate?'无法覆盖类型为' UIScrollViewDelegate?'
  • 的属性
  • '无主'不能应用于非类型的类型' MyScrollViewDelegate?'

如何创建UIScrollView的子类并覆盖委托属性的类型(即使用自定义委托协议)?

6 个答案:

答案 0 :(得分:18)

我认为重写继承属性是Objective-C中可能的,但在Swift中不是(至少目前)。我处理此问题的方法是将单独的委托声明为正确类型的计算属性,以获取并设置实际委托:

@objc protocol MyScrollViewDelegate : UIScrollViewDelegate, NSObjectProtocol {
    func myHeight() -> CGFloat
    // ...
}

class MyScrollView: UIScrollView {
    var myDelegate: MyScrollViewDelegate? {
        get { return self.delegate as? MyScrollViewDelegate }
        set { self.delegate = newValue }
    }
}

这样调用滚动视图委托的任何东西通常都可以工作,你可以在self.myDelegate上调用你的特定委托方法,如下所示:

if let height = self.myDelegate?.myHeight() {
    // ...
}

答案 1 :(得分:3)

我个人喜欢的方法不是直接子类化scrollview,而是创建一个包含并充当单独scrollview委托的UIView子类,然后在必要时将该scrollview的委托消息转发给UIView子类自己的委托。这还允许在滚动视图定义的区域之外添加自定义控件。与直接子类相比,它看起来有点不雅,但它至少可以避免令人不快的黑客攻击。

答案 2 :(得分:3)

这是一个用于更改Swift中覆盖属性类型的解决方案。当您需要扩展委托协议时,它尤其有用。

@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
            }
        }
    }
}

这可以使用Swift 1.2版进行测试。我希望它有所帮助。

答案 3 :(得分:3)

你可以这样做:

protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
    func someNewFunction()
}

class CustomScrollView: UIScrollView {

    weak var myDelegate: ExtendedScrollViewDelegate?
    override weak var delegate: UIScrollViewDelegate? {
        didSet {
            myDelegate = delegate as? ExtendedScrollViewDelegate
        }
    }
}

希望这有帮助

答案 4 :(得分:1)

请考虑以下情况:

class BaseProp {}

class Base {
    var prop: BaseProp
}

然后,如果您这样做:

class DerivedProp: BaseProp {}

class Derived: Base {
    override var prop: DerivedProp
}

然后if会破坏子分类原则(即Liskov替代原则)。基本上,您正在执行的操作是将“ var prop”的范围从较宽的“ BaseProp”类型限制为较窄的“ DerivedProp”类型。这样的代码将是可行的,这是没有道理的:

class UnrelatedProp: BaseProp {}

let derived = Derived()
let base = derived as Base
base.prop = UnrelatedProp()

请注意,我们正在为属性分配UnrelatedProp实例,这对于我们实际使用的Derived实例没有意义。 ObjectiveC允许这种歧义,但是Swift不允许。

答案 5 :(得分:0)

您可以通过声明函数覆盖get和set方法,如:

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

swift将属性编译为方法,如Objective-c那样。