ios - tutorial - Anulando la propiedad delegada de UIScrollView en Swift(como lo hace UICollectionView)
uicollectionview swift 4 (5)
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, usar un protocolo de delegado personalizado)?
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.
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 delegado real :
@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 a delegar la vista de desplazamiento normalmente funciona, y puede llamar a sus métodos de delegado particulares en self.myDelegate
, así:
if let height = self.myDelegate?.myHeight() {
// ...
}
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.
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.
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