Pregunta Anulando la propiedad delegada de UIScrollView en Swift (como lo hace UICollectionView)


UIScrollView tiene una propiedad de delegado que se ajusta a UIScrollViewDelegate

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

UICollectionView anula esta propiedad con un tipo diferente UICollectionViewDelegate

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

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

Cuando intento anular el delegado de UIScrollViews con mi protocolo, así:

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

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

}

el compilador me da dos advertencias:

  • Propiedad 'delegado' con tipo 'MyScrollViewDelegate?' no puede anular una propiedad con el tipo 'UIScrollViewDelegate?'
  • 'Unowned' no se puede aplicar a un tipo que no sea de clase 'MyScrollViewDelegate?'

¿Cómo puedo subclase UIScrollView y anular el tipo de propiedad de delegado (es decir, utilizar un protocolo de delegado personalizado)?


32
2017-09-08 12:50


origen


Respuestas:


Creo que anular una propiedad heredada es algo que es posible en Objective-C pero no (al menos actualmente) en Swift. La forma en que he manejado esto es declarar un delegado separado como una propiedad calculada del tipo correcto que obtiene y establece el real delegar:

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

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

De esta forma, cualquier cosa que llame al delegado de la vista de desplazamiento normalmente funciona, y puede llamar a sus métodos de delegado particulares en self.myDelegate, Me gusta esto:

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

18
2017-09-08 15:07



Aquí hay una solución para cambiar el tipo de las propiedades superiores en Swift. Es especialmente útil cuando necesita extender los protocolos de los delegados.

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

Esto funciona según lo probado con la versión 1.2 de Swift. Espero que ayude.


3
2018-05-27 16:11



Puedes hacer así:

protocol ExtendedUIScrollViewDelegate: UIScrollViewDelegate {
    func someNewFunction()
}

class CustomScrollView: UIScrollView {

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

Espero que esto ayude


3
2017-09-07 03:53



Mi método favorito personalmente no es subclasificar scrollviews directamente sino hacer que una subclase UIView contenga y actúe como delegado para una vista de desplazamiento separada, luego reenviar los mensajes de delegado de la vista de desplazamiento al propio delegado de la subclase UIView cuando sea necesario. Esto también permite la adición de controles personalizados fuera del área definida por la vista de desplazamiento. Puede parecer un poco poco elegante en comparación con una subclase directa, pero al menos evita hacks desagradables.


2
2017-09-28 08:30



Puede anular get y establecer el método mediante la función declare como:

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

compilador rápido la propiedad al método como hace Objective-c.


0
2017-09-17 02:19