Weak references in Swift playground don't work as expected - swift

I have been following the weak referencing example from the Intermediate Swift WWDC session in a Playground. I modified the code slightly 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 referencing, the memory allocated for the instance of Person should be released when it is removed from the renters dictionary because the only other reference to it is weak. However, the output of the programme is different if it is run as a standalone command line application vs. in a Playground (see comments).

I believe the top-level function (REPL/playground) is keeping a strong reference to facilitate interactive behavior, and cleaning up when the frame returns. This behavior eliminates memory leaks in the interactive environment.
I copied Viktor's simple example and used the xcrun swift REPL.
In REPL mode, I wrapped the logic in a function and it works as expected. If/when you care when the memory is cleaned up, 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()

I guess that the Playground itself keeps a strong reference to the object, so the code behaves differently? If that's the case, this could cause some unexpected problems!

I tried an a bit less complex setup of the code.
But did have the same problem in the Playground file, but not in a real command line project.
In a command line project, the output was everything as it should, and in the playground it was Julius does live in a destroyed 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")
}

It is not only weak reference. In playground, the deinit does not work. Since set a variable to nil can not let deinit run, it is not the time weak reference should work.
class MyClass {
init() {
println("ready")
}
deinit {
println("OK")
}
}
var aClass: MyClass?
aClass
aClass = MyClass()
aClass = nil

Update 3: As of 11.3.1: Playground seems to be deiniting objects as expected, as far as I can tell. My original and out of date answer follows: In Xcode 10.1 Playgrounds, I can confirm that deinits are still behaving strangely and I can't use Playgrounds to test whether things are being properly deallocated. Update 1: From another similar thread, I learned that Xcode>New>Project>macOS>Command Line Tool, is a relatively lightweight way to create a generic testing environment that works fine for testing deallocation.
class Person {
let name: String
init(named name: String) { self.name = name }
var house: House?
deinit { print("\(name) is being deinitialized") }
}
class House {
let address: String
init(address: String) { self.address = address }
weak var tenant: Person?
deinit { print("House \(address) is being deinitialized") }
}
func move(_ person: Person, into house: House){
house.tenant = person
person.house = house
}
When Person and House are unconnected, deinits work properly.
However, if I move Buffy into the house, and delete Buffy, because tenant is weak, the Buffy object should be deinited and tenant set to nil. As you can see neither happens.
Even after I delete house (line 38), neither are deinited.
Weak references are behaving like strong references in the Playground.
Wrapping the Run code in a function does not change anything in this example. Update 2: In Xcode 11, As wbennet suggests above, if you wrap your run code in a func and call it, deallocations work for weak references as defined, in Playground.

Related

ARC doesn't deallocate the Object in Array when using remove(at index)

I understand about how ARC decrease the reference count every time the strong reference variable is set to nil, or is out of scope. But in this scenario I confused about why ARC doesn't deallocate the object.
Please take a look at this simple code:
class Person {
var name: String
init(name: String) {
self.name = name
}
deinit {
print("deinit person named \(name)")
}
}
class Main {
func run() {
var personArray = [Person(name: "John"), Person(name: "Doe")]
// This will not deallocate the Person object
personArray.remove(at: 1)
personArray.remove(at: 0)
// This will deallocate the Person Object
// personArray.removeAll()
print("\nEnd of run method\n")
}
}
let main = Main()
main.run()
As you can see here, when I use removeAll() the object is deallocated instantly. You can see the log below:
But when I use remove(at:) the object doesn't get deallocated. As you can see in this log below:
This is just a simple example, but you can see that the ARC doesn't deallocate the object when using remove(at:). Why is that?

Why can I access an object after its deinit method has been called?

I copied most of this code from the Unowned References section in the Swift Guide and ran it in a playground...
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being “deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
var card = john!.card!
john = nil
card.customer.name
john set to nil results in...
"John Appleseed is being “deinitialized\n"
But then getting the name property gives...
"John Appleseed"
So, the customer instance is still accessible despite having being deinitialized!
Shouldn't this result in a nil reference exception? It says in the guide...
Note also that Swift guarantees your app will crash if you try to
access an unowned reference after the instance it references is
deallocated. You will never encounter unexpected behavior in this
situation. Your app will always crash reliably, although you should,
of course, prevent it from doing so.
So, I presume it must not have been deallocated. And yet, the guide also says,
A deinitializer is called immediately before a class instance is
deallocated.
The code works as expected in a regular project, as opposed to a playground.

Safety of unowned in swift

I was reading about unowned from the apple docs.
Like weak references, an unowned reference does not keep a strong hold
on the instance it refers to. Unlike a weak reference, however, an
unowned reference is assumed to always have a value. Because of this,
an unowned reference is always defined as a nonoptional type.
So it seems unowned are similar to weak but they are non optionals.
I was wondering what will happen if when the referenced unowned is deallocated. Why is there no checks like optionals.
I mean I can do something like this,
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
var card: CreditCard? = nil
do {
var john: Customer
john = Customer(name: "John Appleseed")
john.card = CreditCard(number: 1234_5678_9012_3456, customer: john)
card = john.card
}
print("Card belongs to \(card?.customer.name)")
In the last line assuming an unowned to always have a value try to print the name of the card holder, and I got a "Execution was interrupted, reason: EXE_BREAKPOINT..."
I suppose there should not be a problem like this or there should be some kind of safety check at line card = john.card
The checked version of unowned is already there - it is called weak. That is the main difference. unowned is unsafe, but it can make your code clearer is some cases.
unowned references are useful for breaking reference cycles as an alternative to weak when (as the Apple Docs you referenced says) "you know that the reference will never be nil once it has been set during initialisation."
However you have fabricated an example of setting an unowned reference to an object which then goes out of scope making the unowned reference nil.

Swift SpriteKit use struct instead of class to render sprites

I have been updating my game recently to use more value types. I am still not 100% confident with weak and unowned in some cases so I went the struct way to avoid strong reference cycles. As per apples newer keynotes it seems value types are they way to go for the most part anyway.
I have never seen an example where structs are used to render sprites in a spriteKit game so I wonder what the drawbacks are.
I understand that they are copied and not referenced but for my usage it seems to work.
So basically is there something I need to watch out for when doing this
struct Flag {
let post: SKSpriteNode
let flag: SKSpriteNode
init(postImage: String, flagImage: String) {
post = SKSpriteNode(imageNamed: postImage)
// other set ups for post sprite
flag = SKSpriteNode(imageNamed: flagImage)
// other set ups for flag sprite
post.addChild(flag)
}
func animate() {
// code to animate flag
}
}
Than in my SKScenes I simply add them as usual
let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
flag.post.position = ...
addChild(flag.post)
flag.animate()
Now even if I create multiple flags in the same scene I seem to have no problems with this way.
I am just curious because I have never really seen an example like this so I wonder if I am missing something, like performance drawbacks etc.
Thanks for any help.
Personally I avoid creating Structs that contain Classes. Because Structs copy, each and every copy that get's passed around your app will increase the reference count of the Classes. This makes it harder to manage them instead of easier.
It is also useful to take a look at how UIKit uses Structs. A UIView is an object but has many defining properties that are Structs. For example it's frame.
Drop the code below in a playground to see some effects of this behaviour.
The protocol is just to get some meaningful feedback form the playground.
protocol IDLookable : CustomPlaygroundQuickLookable {
var id : Int { get set }
}
extension IDLookable {
func customPlaygroundQuickLook() -> PlaygroundQuickLook {
return PlaygroundQuickLook.AttributedString(NSAttributedString(string: "\(self.dynamicType) with id : \(self.id)"))
}
}
class MyClass : IDLookable {
var id : Int = 0
init(id : Int) {
self.id = id
}
}
struct MyContainerStruct : IDLookable {
var id : Int = 0
var object : MyClass
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 2
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 3
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
// altering the object in one struct will obvously update all references
structContainerTwo.object.id = 1
structContainer.object // 1
structContainerTwo.object // 1
}
}
let test = Scope()
One pattern that does make it easy to work with Reference Types in Value Types is to store them as weak optionals in the Value Types. This means that something will need to have a strong reference but chances are that some Class will be responsible for creating the Structs this is a good place to keep that strong reference.
struct MyContainerStruct : IDLookable {
var id : Int = 0
weak var object : MyClass?
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 1
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 1
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
}
}
let test = Scope()

Swift class: reference cycle

When I run the below program, it produces segmentation fault. Can you please help me figure out why? Thanks
class Animal:NSObject{
var name:String!
var age:UInt!
weak var spouse:Animal?
init(name:String,age:UInt){
self.name=name
self.age=age
}
func description() ->String{ //to become printable
return "name= \(name) and age=\(age) spouse=\(spouse)"
}
}
let dog=Animal(name:"Lucky",age:3)
let cat=Animal(name:"Branson",age:4)
dog.spouse=cat
cat.spouse=dog //It doesnt crash if I comment this line out
println(dog)
The problem is infinite recursion in your printing. Once you set up the full cycle, to print an animal, you print its spouse, which prints its spouse, which print’s its spouse etc. forever until you run out of stack space and crash.
You need to break that by printing out an animal’s spouse without calling the full print of that animal, something like this:
class Animal: NSObject {
// you should avoid using implicitly unwrapped optionals
// unless you absolutely have to for a specific reason that
// doesn’t appear to apply here (so remove the !s)
var name: String
var age: UInt
weak var spouse: Animal?
init(name: String, age: UInt) {
self.name = name
self.age = age
}
}
// to make something printable, you need to conform
// to the Printable protocol
extension Animal: Printable {
// And make description is a var rather than a function
override var description: String {
let spousal_status = spouse?.name ?? "None"
return "name=\(name) and age=\(age), spouse=\(spousal_status)"
}
}
let dog = Animal(name: "Lucky", age: 3)
let cat = Animal(name: "Branson", age: 4)
dog.spouse = cat
dog.description
cat.spouse = dog
println(dog) // Prints name=Lucky and age=3, spouse=Branson
Note, you have to implement Printable fully with the protocol and var to avoid this problem, otherwise you’ll get the default implementation, which will still experience the issue.
btw, Swift style convention is to put spaces between things like =, ->, before { etc. (and in fact you can occasionally cause compilation problems if you don’t). Jury’s still out on a: b vs a:b though I find the latter a bit harder to read.
Your code triggers a stack overflow. The description method contains the spouse description, which will in turn trigger the description of its spouse and so on in a never ending cycle. Try this:
func description() -> String {
return "name= \(name) and age=\(age) spouse=\(spouse?.name)"
}