2015-07-01 16 views
8

Szukam, aby móc wyciągnąć wystąpienie podklasy UIView z końcówki.Używanie 'self' w funkcjach rozszerzających klasy w Swift

Chciałbym móc wywoływać MyCustomView.instantiateFromNib() i mieć instancję MyCustomView. Jestem prawie gotowy, aby po prostu przesłać działający kod Objective-C jaki posiadam przez nagłówek pomostowy, ale pomyślałem, że najpierw spróbuję podejścia idiomatycznego. To było dwie godziny temu.

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

Teraz if (topLevelObject is self) { jest błędne, ponieważ "Oczekiwany typ po 'jest'". To, co próbowałem później, pokazuje wiele rzeczy, których nie rozumiem w systemie typu Swift.

  • if (topLevelObject is Self) {
  • if (topLevelObject is self.dynamicType) {
  • if (topLevelObject is self.self) {
  • milion innych zmian, które są not even wrong.

Dowolny wgląd jest mile widziany.

Odpowiedz

14

Stosując podejście od How can I create instances of managed object subclasses in a NSManagedObject Swift extension? można zdefiniować ogólne metody pomocnika, który wywodzi typ self z kontekstu wywołującego:

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

To kompiluje i działa zgodnie z oczekiwaniami w moim szybkiego testu. Jeśli MyCustomView to UIView podklasa następnie

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

daje instancję MyCustomView, a typ jest wywnioskować automatycznie.


Aktualizacja 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 
    } 
} 
+1

Fantastyczne!Zanurzyłem swój palec w ogólnych metodach, aby spróbować rozwiązać ten problem i nie zdałem sobie z tego sprawy. Dzięki! – rob5408

+0

Znalazłem dziwny błąd w tym miejscu, w którym działa on na symulatorze i na urządzeniu, jeśli jest to wykonywane przez programistę, ale w powietrzu nie używa klasy widoku określonej w stalówce. Występują awarie zgłaszające, że inny widok z innym typem jest zwracany i traktuję go jako oczekiwany typ. Dziwne. – rob5408

+0

Przełączanie flagi poziomu optymalizacji dla wersji wydań na Brak działało. Teraz muszę wymyślić, jak to naprawić. – rob5408

2

wierzę wyrażenie warunkowe szukasz jest topLevelObject.dynamicType == self

Łącząc to z unsafeBitCast(which, by Apple's own documentation, "Breaks the guarantees of Swift's type system"), możemy mocno przygnębiony topLevelObject do self typ. Ten powinny pewności, bo już na pewno, że topLevelObject jest tego samego typu jak self

Jest jeden sposób, aby ominąć metody pomocnika przy użyciu rodzajowych, że opisane 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 
    } 
} 

Zauważ, że Apple mówi również w ich dokumentacji unsafeBitCast:

Jest prawie zawsze lepszy sposób do niczego.

Bądź więc ostrożny!