1

Die Beispiele für starke Referenzzyklen, die ich normalerweise sehe, beziehen sich auf zwei Klassen mit Eigenschaften, die zueinander zeigen. Was aber, wenn nur eine der Klassen eine Eigenschaft hat, wie diese auf die andere Instanz zeigen:Ist das ein starker Referenzzyklus oder ein Speicherleck überhaupt?

class ClassA { 
    var classB: ClassB? = nil 
} 

class ClassB { 

} 

Dann erstelle ich meine Instanzen wie folgt aus:

var myClassA = ClassA() 
var myClassB = ClassB() //Reference count 1 
myClassA.classB = myClassB //Reference count 2 

// Now deallocate 
myClassB = nil //Reference count 1 
myClassA = nil 

Seit ich myClassB ausgeplant, die Referenzzählung ist 1. Was ist mit der Referenzzählung von passiert? Es hat nie Null erreicht, da ich nie myClassA.classB = nil oder deinit getan habe, um dies zu tun. Ist das implizit getan, seit ich myClassA = nil getan habe?

Kann dies als ein starker Referenzzyklus kategorisiert werden? Ich könnte mir vorstellen, dass es zumindest ein Speicherleck ist, ist das wahr?

+2

In Ihrem Code gibt es weder eine Leckage noch einen Zirkelverweis. Wenn Sie 'myClassA' auf' nil' setzen, bricht ARC automatisch den Besitz von 'ClassB', so dass beide freigegeben werden. – ozgur

+0

Um darauf zu erweitern - es gibt keinen Zyklus, da Ihr Graph nur eine Kante hat: 'myClassA.classB -> myClassB'. – jtbandes

+0

Wenn dieser Code eine Verknüpfung verursachte, würde ARC nur marginal nützlich sein. Alle Referenzen, die auf Instanzenebene gehalten werden, werden freigegeben, wenn die Instanz freigegeben wird. – Avi

Antwort

2

Wie @ozgur, @jtbandes, @Avi und @Rob in den Kommentaren erklärt, gibt es keinen starken Referenzzyklus oder Leck. Hier

ist ein Beispiel, basierend auf @ Robs Kommentar, die Sie in einem Spielplatz laufen können:

class ClassA { 
    var classB: ClassB? 

    deinit { 
     print("ClassA deallocated") 
    } 
} 

class ClassB { 
    deinit { 
     print("ClassB deallocated") 
    } 
} 

class Tester { 
    func test() { 
     var myClassA: ClassA! = ClassA() 
     var myClassB: ClassB! = ClassB() //Reference count 1 
     myClassA.classB = myClassB //Reference count 2 

     // Now deallocate 
     print("setting myClassB to nil") 
     myClassB = nil //Reference count 1 
     print("setting myClassA to nil") 
     myClassA = nil 
     print("all done") 
    } 
} 

// Create `Tester` object and call `test`: 

Tester().test() 

Ausgang:

setting myClassB to nil 
setting myClassA to nil 
ClassA deallocated 
ClassB deallocated 
all done 

Die Sache ist zu beachten, dass, obwohl Sie set myClassB zu nil zuerst, dass myClassA wird zuerst freigegeben. Wenn myClassA freigegeben wird, wird der letzte Verweis auf myClassB von ARC freigegeben und dann wird myClassB freigegeben.


Um einen starken Referenzzyklus zu demonstrieren, haben ClassB einen starken Bezug auf ClassA behalten:

class ClassA { 
    var classB: ClassB? 

    deinit { 
     print("ClassA deallocated") 
    } 
} 

class ClassB { 
    var classA: ClassA? 

    deinit { 
     print("ClassB deallocated") 
    } 
} 

class Tester { 
    func test() { 
     var myClassA:ClassA! = ClassA() 
     var myClassB:ClassB! = ClassB() //Reference count 1 
     myClassA.classB = myClassB //Reference count 2 
     myClassB.classA = myClassA 

     // Now deallocate 
     print("setting myClassB to nil") 
     myClassB = nil //Reference count 1 
     print("setting myClassA to nil") 
     myClassA = nil 
     print("all done") 
    } 
} 

Tester().test() 

Ausgang:

setting myClassB to nil 
setting myClassA to nil 
all done 

Weder Objekt ist freigegeben, wenn sie beide enthalten starke Bezugnahme auf die andere. Um diesen starken Referenzzyklus zu unterbrechen, deklarieren Sie eine der Eigenschaften classB oder classA als weak.Welche Sie wählen, wirkt sich die Reihenfolge, dass die Objekte frei zu bekommen:

Wenn Sie weak var classB: ClassB in ClassA erklären:

Ausgang:

setting myClassB to nil 
ClassB deallocated 
setting myClassA to nil 
ClassA deallocated 
all done 

Wenn stattdessen Sie erklären weak var classA: ClassA in ClassB:

Ausgabe: