web-dev-qa-db-ja.com

Swift(UICollectionViewのように)でUIScrollViewのデリゲートプロパティをオーバーライドする

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?

}

コンパイラーは2つの警告を出します。

  • タイプ「MyScrollViewDelegate?」のプロパティ「delegate」タイプが「UIScrollViewDelegate?」のプロパティをオーバーライドできません
  • 'unowned'は非クラスタイプ 'MyScrollViewDelegate?'に適用できません

UIScrollViewをサブクラス化してデリゲートプロパティのタイプをオーバーライドするにはどうすればよいですか(つまり、カスタムデリゲートプロトコルを使用します)?

36
stringCode

継承されたプロパティのオーバーライドはObjective-Cでは可能ですが、(少なくとも現在のところ)Swiftでは不可能です。これを処理する方法は、別のデリゲートを、actualデリゲートを取得および設定する正しいタイプの計算プロパティとして宣言することです。

@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() {
    // ...
}
18
Nate Cook

あなたはこのようにすることができます:

protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
    func someNewFunction()
}

class CustomScrollView: UIScrollView {

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

お役に立てれば

4
谢仪伦

私が好む方法は、直接スクロールビューをサブクラス化するのではなく、UIViewサブクラスに別のスクロールビューのデリゲートを含めて機能させ、必要に応じてそのスクロールビューのデリゲートメッセージをUIViewサブクラスの独自のデリゲートに転送することです。これにより、スクロールビューで定義された領域の外にカスタムコントロールを追加することもできます。直接のサブクラスに比べて少しエレガントではないように見えるかもしれませんが、少なくとも不快なハッキングは避けられます。

3
Ash

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
prodos

次の状況を検討してください。

class BaseProp {}

class Base {
    var prop: BaseProp
}

次に、これを行うと:

class DerivedProp: BaseProp {}

class Derived: Base {
    override var prop: DerivedProp
}

次に、サブクラスの原則(つまり、リスコフの代替原則)を破る場合。基本的には、「var prop」のスコープをより広い「BaseProp」タイプからより狭い「DerivedProp」タイプに制限しています。次に、この種のコードは可能ですが、意味がありません。

class UnrelatedProp: BaseProp {}

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

プロパティにUnrelatedPropのインスタンスを割り当てていることに注意してください。これは、実際に操作するDerivedインスタンスには意味がありません。 ObjectiveCはこのようなあいまいさを許容していますが、Swiftはそうではありません。

1
Igor Vasilev

次のような関数を宣言することで、getおよびsetメソッドをオーバーライドできます。

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

Objective-cと同様に、Swiftコンパイラーがプロパティをメソッドに変換します。

0
thilong