2015-04-09 29 views
9

Tworzę podklasę MKAnnotationView w moim projekcie. Musi mieć dwie właściwości do przechowywania subskrybentów, które muszę zainicjować gdzieś na początku.jakie inicjatory powinna mieć podklasa MKAnnotationView w Swift?

MKAnnotationView ma jeden inicjator wymienione w dokumentacji, initWithAnnotation:reuseIdentifier:, więc pomyślałem, że po prostu zastąpić że:

class PulsatingDotMarker: MKAnnotationView { 

    let innerCircle: UIView 
    let outerCircle: UIView 

    override init!(annotation: MKAnnotation!, reuseIdentifier: String!) { 
     innerCircle = ... 
     outerCircle = ... 

     super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) 
    } 

    ... 
} 

Ale to powoduje wyjątek środowiska wykonawczego:

fatal error: use of unimplemented initializer 'init(frame:)' for class 'PulsatingDotMarker'

Ok, więc ja domyślam się initWithAnnotation:reuseIdentifier: wewnętrznie dzwoni initWithFrame:, więc prawdopodobnie to powinienem zastąpić. Spróbujmy że:

class PulsatingDotMarker: MKAnnotationView { 

    let innerCircle: UIView 
    let outerCircle: UIView 

    override init(frame: CGRect) { 
     innerCircle = ... 
     outerCircle = ... 

     super.init(frame: frame) 
    } 

    ... 
} 

To jednak powoduje błąd kompilacji podczas tworzenia obiektu widoku adnotacji:

Extra argument 'reuseIdentifier' in call

Hmm, więc jeśli wdrożenie (wymagane) inicjator initWithFrame:, to teraz traci domyślny inicjatora initWithAnnotation:reuseIdentifier:?

Może po dodaniu przesłonięcia initWithAnnotation:reuseIdentifier:, które po prostu zadzwoni super, będzie ponownie dostępne, czy to zadziała?

class PulsatingDotMarker: MKAnnotationView { 

    let innerCircle: UIView 
    let outerCircle: UIView 

    init!(annotation: MKAnnotation!, reuseIdentifier: String!) { 
     super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) 
    } 

    override init(frame: CGRect) { 
     innerCircle = ... 
     outerCircle = ... 

     super.init(frame: frame) 
    } 

    ... 
} 

Nie, nadal nie jest dobra - błąd kompilacji:

Property 'self.innerCircle' not initialized at super.init call

Ok, gdybym miał initWithFrame:, ale zainicjowaniu subviews w initWithAnnotation:reuseIdentifier:? (? Ale co jeśli ktoś po prostu wywołuje initWithFrame: bezpośrednio ...)

class PulsatingDotMarker: MKAnnotationView { 

    let innerCircle: UIView 
    let outerCircle: UIView 

    init!(annotation: MKAnnotation!, reuseIdentifier: String!) { 
     innerCircle = ... 
     outerCircle = ... 

     super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
    } 

    ... 
} 

Nic dziwnego, że Swift chroni mnie od tego, mówiąc mi:

Property 'self.innerCircle' not initialized at super.init call

(tym razem w initWithFrame:).

Co powinienem zrobić? Nie mogę utworzyć subviews zarówno tutaj, jak i tam, prawda?

class PulsatingDotMarker: MKAnnotationView { 

    let innerCircle: UIView 
    let outerCircle: UIView 

    init!(annotation: MKAnnotation!, reuseIdentifier: String!) { 
     innerCircle = ... 
     outerCircle = ... 

     super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) 
    } 

    override init(frame: CGRect) { 
     innerCircle = ... 
     outerCircle = ... 

     super.init(frame: frame) 
    } 

    ... 
} 

Źle ponownie, to rzeczywiście działa - choć jestem przypisywania stałą właściwość dwa razy w tym samym obiekcie (!).

Czy ktoś ma pomysł, jak to zrobić prawidłowo?

(Uwaga: klasa obejmowała również wymagane initWithCoder: inicjator że po prostu wywołuje fatalError z pierwszego przykładu, ale obiekt nie jest tworzony z serii ujęć.)

+0

Co jeśli subviews są zadeklarowane jako 'var innerCircle: UIView!'? Może to uniknąć błędów "wymaganych init (xxx)". – Anna

+0

Dokładnie to zrobiłem, ale brzmi to jak włamanie - oznaczanie właściwości jako zerowalnej i zmienne, nawet jeśli powinno być niezerowe i stałe, żeby zadowolić kompilator ... –

+0

Spędziłem trochę czasu na podobnych problemach, i wykonałem projekt testowy, w którym, jak sądzę, udało mi się wypracować przyczynę (klasa Objective C nazywająca metodę '[self initWith ...]' w swojej publicznej metodzie 'init'), ale niestety nie ma jeszcze rozwiązań - http://stackoverflow.com/questions/31161143/non-designated-initialiser-inheritance- from-objective-c-classes – Rupert

Odpowiedz

2

Dla mojej aplikacji, rozwiązanie wybrałem jest zadeklarować podgląd jako opcjonalny i utworzyć instancję w initFrame ...

var innerCircle: UIView?

Oto mój kod ...

class EventAnnotationView: MKPinAnnotationView 
{  
    static var REUSE_ID = "EventAnnotationView" 

var imageView: UIImageView? 

override init(frame: CGRect) 
{ 
    super.init(frame: frame) 

    // Create subview for custom images 
    imageView = UIImageView(frame: CGRectMake(0, 0, 22, 22)) 

    ... 

} 

override init(annotation: MKAnnotation!, reuseIdentifier: String!) 
{ 
    super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) 
} 

required init(coder aDecoder: NSCoder) 
{ 
    super.init(coder: aDecoder) 
} 
} 

Czuje się jakby mniej hack :), ale wymaga więcej kodu/pracy od subview jest opcjonalne.

Mam nadzieję, że to pomoże.

8

Niestety dla MKAnnotationView wymusza wdrożenie init(frame: CGRect), co oznacza, że ​​należy również zainicjować wszystkie zmienne instancji w tej metodzie.

This article wyjaśnia to trochę więcej

Dla zmiennych, które można zainicjować tylko przeszła w wartościach trzeba zrobić te zmienne opcjonalne i ustawić je do zera w init(frame: CGRect).

Powodem tego jest podejrzenie, że MKAnnotationView wywołuje self.initWithFrame: rect w swojej metodzie init-C init. Jest tak, że jeśli podklasa zastąpi initWithFrame:(CGRect) rect, zostanie wywołana. Powoduje to jednak problem w szybkim tempie, ponieważ jeśli zadeklarujesz niestandardowy inicjator, nie odziedziczysz inicjalizatorów nadklasy. Dlatego musisz wdrożyć init(frame: CGRect) w swojej podklasie.

Miałem ten sam problem z UITableVeiwController. Jego nagłówek wygląda tak samo. tj. dwa konfigurowalne wyznaczone inicjatory.

Bardzo mnie to zasmuca. Ale co możesz zrobić.

0

Jest oczywiste, że coś faktycznie złamane w Swift 3, ponieważ dany inicjator nie jest faktycznie wywoływany przez iOS w czasie wykonywania.

znalazłem sugestia w innych odpowiedzi nie skompilować (Testowane na XCode 8.1 GM/iOS 10,1), ale po różnych hacking wokół znalazłem to kombinacja działa:

override init(annotation: MKAnnotation?, reuseIdentifier: String?) { 
    super.init(annotation: annotation, reuseIdentifier: reuseIdentifier); 

    /* Your actual init code */ 
} 

convenience init(frame: CGRect) { 
    self.init(annotation: nil, reuseIdentifier: nil); 
}