Ios 在Swift中重写UIScrollView的委托属性(与UICollectionView类似)

Ios 在Swift中重写UIScrollView的委托属性(与UICollectionView类似),ios,swift,uiscrollview,uiscrollviewdelegate,Ios,Swift,Uiscrollview,Uiscrollviewdelegate,UIScrollView具有符合UIScrollViewDelegate的委托属性 protocol UIScrollViewDelegate : NSObjectProtocol { //... } class UIScrollView : UIView, NSCoding { unowned(unsafe) var delegate: UIScrollViewDelegate? //... } protocol UICollectionViewDelegate :

UIScrollView具有符合UIScrollViewDelegate的委托属性

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

class UICollectionView : UIScrollView {
     unowned(unsafe) var delegate: UICollectionViewDelegate?
   //...
}
UICollectionView使用不同类型的UICollectionViewDelegate重写此属性

protocol UIScrollViewDelegate : NSObjectProtocol {
    //...
}
class UIScrollView : UIView, NSCoding {
    unowned(unsafe) var delegate: UIScrollViewDelegate?
    //...
}
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”的属性“delegate”无法重写类型为“UIScrollViewDelegate”的属性
  • “unowned”不能应用于非类类型“MyScrollViewDelegate”

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

我认为覆盖继承属性在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 }
    }
}
这样,任何调用scroll view委托的操作都正常工作,您可以在
self.myDelegate
上调用特定的委托方法,如下所示:

if let height = self.myDelegate?.myHeight() {
    // ...
}
protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
    func someNewFunction()
}

class CustomScrollView: UIScrollView {

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

您可以通过以下声明函数重写get和set方法:

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

swift编译器像Objective-c一样将属性转换为方法。

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

下面是一个在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的测试结果相同。我希望有帮助。

您可以这样做:

if let height = self.myDelegate?.myHeight() {
    // ...
}
protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
    func someNewFunction()
}

class CustomScrollView: UIScrollView {

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

希望这有助于考虑以下情况:

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的一个实例分配给属性,这对于我们实际使用的派生实例没有意义。ObjectiveC允许这种模糊性,但Swift不允许。

您能更详细地描述一下或发布一些代码吗?这看起来很有趣……这在Swift 2.1上不起作用,对这种方法有任何更新吗?这对我不起作用。我有一个纯粹的Swift应用程序。在将此setter方法添加到我的
UITextView
子类之后,从委托(我的视图控制器)执行
myTextView.delegate=self
并没有调用我添加的setter方法。我没有尝试getter方法。