Подтвердить что ты не робот

Переопределение свойства делегата UIScrollView в Swift (например, UICollectionView)

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?

}

компилятор дает мне два предупреждения:

  • Свойство 'delegate' с типом 'MyScrollViewDelegate'? не может переопределить свойство с типом 'UIScrollViewDelegate?'
  • "unowned" не может применяться к типу неклассов "MyScrollViewDelegate?"

Как я могу подклассифицировать UIScrollView и переопределить тип свойства делегата (т.е. использовать пользовательский протокол делегатов)?

4b9b3361

Ответ 1

Я думаю, что переопределение унаследованного свойства - это то, что возможно в 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() {
    // ...
}

Ответ 2

Вот решение для изменения типа переопределяющих свойств в 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

Вы можете сделать следующее:

protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
    func someNewFunction()
}

class CustomScrollView: UIScrollView {

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

Надеюсь, что это поможет

Ответ 4

Мой предпочтительный метод лично не относится к подзапросам scrollviews напрямую, но для создания подкласса UIView, содержащего и действующего как делегат для отдельного прокрутки, а затем пересылать эти сообщения делегатов scrollview в собственный делегат подкласса UIView, где это необходимо. Это также позволяет добавлять пользовательские элементы управления вне области, определенной в виде прокрутки. Это может показаться немного неэлегантным по сравнению с прямым подклассом, но он по крайней мере избегает неприятных хаков.

Ответ 5

Рассмотрим следующую ситуацию:

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 этого не делает.

Ответ 6

Вы можете переопределить метод get и set с помощью функции declare, например:

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

swift-компилятор свойство для метода как Objective-c делает.