2014-06-07 18 views
42

Kilka razy natknąłem się na ten problem podczas przenoszenia kodu Objective-C do Swift. Że mam następujący kod:Używanie dispatch_async z self

dispatch_async(dispatch_get_main_queue()) { 
    self.hostViewController?.view.addSubview(self.commandField) 
} 

spowoduje to wystąpienie błędu, podkreślając całą dispatch_async połączeń, oferując:

Zakładam, że to jest błąd, który jeszcze nie został prawidłowo wdrożony ponieważ jeśli wstawię wywołanie addSubview poza blokiem dispatch_async, projekt zostanie poprawnie zbudowany. Początkowo zakładałem, że może to mieć coś wspólnego z przechwytywaniem self w bloku. Wstawienie [unowned self] in powoduje jednak ten sam błąd, co w przypadku [weak self] in (po wstawieniu odpowiednich operatorów odwijających !).

Jak mogę uzyskać dispatch_async bloki do pracy w Swift, które muszą przechwycić self?

Odpowiedz

65

powinien warunkować wydzielenie tej czynności na non-nieważności, nie przetestować na nim po tym, jak już zainicjowany go:

if let hostView = self.hostViewController?.view { 
    DispatchQueue.main.async { 
     hostView.addSubview(self.commandField) 
    } 
} else { 
    // handle nil hostView 
} 

Nigdy nie należy rozpakować opcjonalnej zewnętrznej stronie if let lub sprawdzając je pierwszy. Takie postępowanie powinno również rozwiązać problem twojego słabego ja.

+0

Ah, który działa, dzięki! Czy kompilator narzeka, że ​​nie może deterministycznie rozwinąć 'hostController? 'Wewnątrz bloku? Czy coś tu się dzieje? – Ephemera

+5

To dlatego, że wyrażenie 'self.hostViewController? .view' zwraca obiekt typu' NSView? ', * Nie *' NSView'. Opcjonalne łańcuchy zawsze muszą zostać sprawdzone, a wynik musi zostać przepuszczony lub wymuszony. – iluvcapra

12

Składnia dispatch_async zmieniła się z Swift 3:

DispatchQueue.main.async { 
    hostView.addSubview(self.commandField) 
}