2017-11-27 5 views
-2

Die Frage ist wirklich einfach. Ich weiß Retain-Zyklen zu erkennen, aber ich möchte wissen, ob ich im nächsten Beispiel Zyklus behalten habe.Swift - Zyklus nicht mit Selbst beibehalten?

MainManager.sound.player.speak("1", didFinish: { 

     MainManager.sound.player.speak("3", didFinish: { 

      MainManager.sound.player.speak("4", didFinish: { 

      }) 
     }) 
    }) 

MainManager ist eine Singleton-Klasse, die sound in einem starken ref zu halten, und sound halten player Klasse in stark ref.

Die Umsetzung sprechen()

private var speechSynthesizer:AVSpeechSynthesizer? 
private var speechDidFinishCompletion:CompletionVoid? = nil 
func speak(_ stringToSpeak:String, didFinish:CompletionVoid? = nil) 
{ 
    if speechSynthesizer == nil 
    { 
     speechSynthesizer = AVSpeechSynthesizer() 
     speechSynthesizer?.delegate = self 
    } 

    speechDidFinishCompletion = didFinish 

    let speechUtterance = AVSpeechUtterance(string: stringToSpeak) 
    speechSynthesizer!.speak(speechUtterance) 
} 

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) 
{ 
    speechDidFinishCompletion?() 
} 
+0

Könnten Sie die Implementierung der 'speak' Methode posten? –

+0

Zyklus mit was genau beibehalten? Nach dem Aussehen der Dinge, beziehen Sie sich nur auf statische Mitglieder. Es wäre sehr hilfreich, wenn Sie mehr Kontext bereitstellen könnten. – Hamish

+0

i'v nur die Frage bearbeiten können Sie einen Blick pls? –

Antwort

1

Die Antwort ist "es kommt".

Wenn MainManager einen starken Bezug auf sound hat und sound hat einen starken Bezug auf player und player.speak() macht player halten einen starken Bezug auf die Schließung, die sie nicht loswerden kann, dann ja, haben Sie einen starken Referenzzyklus.

Wenn jedoch speak nur die Schließung in eine asynchrone Warteschlange legt und nie wieder verweist, werden Sie in Ordnung sein.

+0

Danke, ich bearbeite nur die Frage können Sie einen Blick pls? –

0

Sie haben einen potenziellen Aufbewahrungszyklus, weil Sie die Referenz nicht loslassen, nachdem Sie den Beendigungshandler aufgerufen haben. Solange die Schließung nicht mehr von der Instanz sound referenziert wird, kann der Zyklus unterbrochen werden. Ihr aktueller "rekursiver" Aufruf stellt sicher, dass die ersten 2 Callbacks freigegeben werden, da sie von den nachfolgenden Aufrufen überschrieben werden. Da der letzte Code nicht überschrieben wird und der letzte Closure einen Retain-Zyklus hat, erzeugt dieser Code einen Zyklus.

Sie sollten den Verweis auf den Beendigungshandler wie folgt sicher entfernen können.

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) { 
    // Transfer ownership to the local scope in case the 
    // closure itself sets `speechDidFinishCompletion` 
    let localClosure = speechDidFinishCompletion 
    speechDidFinishCompletion = nil 

    localClosure?() 
} 
+0

sieht gut aus, habe nicht darüber nachgedacht :) –