swift

Usar ''self'' en funciones de extensión de clase en Swift



(2)

Creo que la expresión condicional que está buscando es topLevelObject.dynamicType == self

Combinando esto con unsafeBitCast (que, según la propia documentación de Apple, "Rompe las garantías del sistema de tipos de Swift") , podemos topLevelObject forzosamente topLevelObject para topLevelObject self . Esto debería ser seguro porque ya nos aseguramos de que topLevelObject sea ​​del mismo tipo que self

Esta es una forma de sortear el método auxiliar utilizando los genéricos que describió Martin R.

extension UIView { class func instantiateFromNib() -> Self? { let bundle = NSBundle.mainBundle().loadNibNamed("CustomViews", owner: nil, options: nil) for topLevelObject in topLevelObjects { if topLevelObject.dynamicType == self { return unsafeBitCast(topLevelObject, self) } } return nil } }

Tenga en cuenta que Apple también dice en su documentación para unsafeBitCast :

Casi siempre hay una mejor manera de hacer cualquier cosa.

¡Así que ten cuidado!

Estoy buscando poder extraer una instancia de una subclase UIView de un Nib.

Me gustaría poder llamar a MyCustomView.instantiateFromNib () y tener una instancia de MyCustomView. Estoy casi listo para portar el código de Objective-C que tengo a través del encabezado de puente, pero pensé que primero probaría el enfoque idiomático. Eso fue hace dos horas.

extension UIView { class func instantiateFromNib() -> Self? { let topLevelObjects = NSBundle.mainBundle().loadNibNamed("CustomViews", owner: nil, options: nil) for topLevelObject in topLevelObjects { if (topLevelObject is self) { return topLevelObject } } return nil } }

Ahora if (topLevelObject is self) { está mal porque "Tipo esperado después de ''is''". Lo que he intentado después de eso muestra mucho sobre lo que no entiendo sobre el sistema de tipos Swift.

  • if (topLevelObject is Self) {
  • if (topLevelObject is self.dynamicType) {
  • if (topLevelObject is self.self) {
  • Un millón de otras variaciones que ni siquiera están mal .

Cualquier idea es apreciada.


Uso del enfoque de ¿Cómo puedo crear instancias de subclases de objetos administrados en una extensión NSManagedObject Swift? puede definir un método auxiliar genérico que infiere el tipo de self desde el contexto de llamada:

extension UIView { class func instantiateFromNib() -> Self? { return instantiateFromNibHelper() } private class func instantiateFromNibHelper<T>() -> T? { let topLevelObjects = NSBundle.mainBundle().loadNibNamed("CustomViews", owner: nil, options: nil) for topLevelObject in topLevelObjects { if let object = topLevelObject as? T { return object } } return nil } }

Esto compila y funciona como se esperaba en mi prueba rápida. Si MyCustomView es su subclase de UIView entonces

if let customView = MyCustomView.instantiateFromNib() { // `customView` is a `MyCustomView` // ... } else { // Not found in Nib file }

le da una instancia de MyCustomView , y el tipo se infiere automáticamente.

Actualización para Swift 3:

extension UIView { class func instantiateFromNib() -> Self? { return instantiateFromNibHelper() } private class func instantiateFromNibHelper<T>() -> T? { if let topLevelObjects = Bundle.main.loadNibNamed("CustomViews", owner: nil, options: nil) { for topLevelObject in topLevelObjects { if let object = topLevelObject as? T { return object } } } return nil } }