Weak links on the Swift playground do not work properly

I followed a weak example of links from an Intermediate Swift WWDC session on a playground. I slightly modified the code as follows:

class Apartment { let address: Int init(address: Int) { self.address = address } weak var tenant: Person? } class Person { let name: String init(name: String){ self.name = name } weak var home: Apartment? func moveIn(apt: Apartment) { self.home = apt apt.tenant = self } } var renters = ["John Appleseed": Person(name: "John Appleseed")] var apts = [16: Apartment(address: 16)] renters["John Appleseed"]!.moveIn(apts[16]!) renters["John Appleseed"] = nil // memory should be released here // then apts[16].tenant should be nil if let tenantName = apts[16]!.tenant?.name { // this should only execute if the Person object is still in memory println("\(tenantName) lives at apartment number \(apts[16]!.address)") } else { // and this line should execute if the memory is released as we expect println("Nobody lives at apartment number \(apts[16]!.address)") } // Console output in Playground: John Appleseed lives at apartment number 16 // Console output in standalone app: Nobody lives at apartment number 16 

From my understanding of weak references, the memory allocated for the Person instance should be released when it is removed from the tenants dictionary, because the only other reference to it is weak. However, the output of the program is different if it runs as a separate command-line application and on the playground (see. Comments).

+6
source share
4 answers

I believe the top-level function (REPL / playground) maintains a strong link to facilitate interactive behavior and cleanup when the frame returns. This behavior resolves memory leaks in an interactive environment.

I copied a simple Viktor simple example and used xcrun swift REPL.

In REPL mode, I wrapped the logic in a function and works as expected. If / when you care when the memory is cleared, I would suggest wrapping your logic in a function.

 // declaration of the types class Person { let name: String weak var home: Apartment? init(pName: String){ name = pName } } class Apartment { let postalCode: Int init(pPostalCode: Int) { postalCode = pPostalCode } } func testArc() { // create Person object var personJulius: Person = Person(pName: "Julius") // create Apartment object var apartmentBerlin: Apartment? = Apartment(pPostalCode: 10777) // connect Apartment object and Person object personJulius.home = apartmentBerlin // Set only strong reference of Apartment object to nil apartmentBerlin = nil // Person object should now have nil as home if personJulius.home != nil { println("Julius does live in a destroyed apartment") } else { println("everything as it should") } } //outputs "everything as it should" testArc() 
+3
source

I assume the playground itself maintains a strong reference to the object, so does the code behave differently? If this happens, it may cause some unexpected problems!

+2
source

I tried a bit more complicated code setup. But they had the same problem in the Playground file , but not in the real command line project .

In the draft command line, the way out was everything as it should, and on the playground, Julius really lived in a ruined apartment.

 import Cocoa // declaration of the types class Person { let name: String weak var home: Apartment? init(pName: String){ name = pName } } class Apartment { let postalCode: Int init(pPostalCode: Int) { postalCode = pPostalCode } } // create Person object var personJulius: Person = Person(pName: "Julius") // create Apartment object var apartmentBerlin: Apartment? = Apartment(pPostalCode: 10777) // connect Apartment object and Person object personJulius.home = apartmentBerlin // Set only strong reference of Apartment object to nil apartmentBerlin = nil // Person object should now have nil as home if personJulius.home != nil { println("Julius does live in a destroyed apartment") } else { println("everything as it should") } 
+2
source

This is not only a weak link. On the playground, deinit does not work. Since setting a variable in nil does not allow deinit to run, this does not mean that weak link time should work. deinit does not run

 class MyClass { init() { println("ready") } deinit { println("OK") } } var aClass: MyClass? aClass aClass = MyClass() aClass = nil 
0
source

Source: https://habr.com/ru/post/970450/


All Articles