memory leak with swift due to reference cycle - swift

Can someone please help me to avoid memory leak below
class Base {
var refer: Referenced?
init() {
self.refer = Referenced()
}
deinit {
print("deinit called")
}
}
class Referenced {
var native: Native
init(){
native = Native.init(baseRef: Base())
}
}
struct Native {
var baseRef: Base
}
func testMe () {
var base:Base? = Base()
base?.refer = nil
base = nil
}
testMe()
Looks like there is a cyclic reference in here. Base -> Referenced and Referenced -> Native -> Base
But I am unsure how to break this cycle .

There are two issues here:
As others have pointed out, in general, when you have two or more reference types referring to each other, you need to make one of those references weak to break the strong reference cycle. See Resolving Strong Reference Cycles Between Class Instances.
The more serious problem here is that you have infinite loop. The init of Base is instantiating a new Referenced instance, but the init of Referenced is creating another Base instance (which it’s passing to the Native instance). That new Base instance will then create another Referenced instance, repeating the process, and it will continue doing this until it runs out of memory/stack.
Add print statements inside your various init methods, and you’ll see this infinite loop in action.
You should revisit this model, identify an “ownership” graph. Parent objects can keep strong references to child objects (and possibly instantiate child objects, if appropriate), but child objects should only keep weak references back to their parent objects (and most likely not instantiate new parent objects).
For example, you might do:
class Parent {
var child: Child?
init() {
self.child = Child(parent: self)
}
deinit {
print("deinit called")
}
}
class Child {
weak var parent: Parent?
init(parent: Parent) {
self.parent = parent
}
}
And
func testMe() {
var parent: Parent? = Parent()
parent = nil // in this case, this is unnecessary because `parent` is a local variable, but this is here for illustrative purposes; but note that we don’t have to `nil` the `child`
}
Here, you instantiate a Parent object, which happens to instantiate a child. But note that:
The Parent supplies itself as a parameter to the Child;
The Child only maintains a weak reference back to the Parent; and
The Child obviously does not instantiate a new Parent, but rather just uses the reference that was supplied to it.
You can do a rendition of this with your Native struct, too, but the idea will be the same: Break the strong reference cycle with a weak reference and avoid the infinite loop.
Frankly, in these cases, abstract type names make examples unnecessarily confusing. If you clarify what these various types actual represent with a practical, real-world example, the ownership model will undoubtedly become more self-evident.

Change one of the reference as weak like this :
class Base {
weak var refer: Referenced?
init() {
self.refer = Referenced()
}
deinit {
print("deinit called")
}
}
Hope this helps.

You need to mark either Base.refer or Native.baseRef as weak to break the cycle, i.e. change var to weak var.

First of all, at the code snippet you passed, you have a problem with infinite circular dependency like this:
Base -> Referenced -> Native -> Base...
An instance of Native struct is not referencing the Base instance at the beginning of this chain, it is always creating a new one and this behavior is infinite. Just copy your code to the playground and try to run it. You will receive an "Execution was interrupted" error.
So, your code won't even run. As I suppose, what you are trying to achieve is for a Native struct to hold the reference to the first Base instance. Here is the right solution where we pass the reference from Base to Referenced and to Native that will hold the reference:
class Base {
var refer: Referenced?
init() {
self.refer = Referenced(base: self)
}
deinit {
print("deinit called")
}
}
class Referenced {
var native: Native
init(base: Base){
native = Native.init(baseRef: base)
}
}
struct Native {
var baseRef: Base
}
And now, as Native is referencing to the Base parent, you will struggle with the memory leak you mention in the original question. And this time, to prevent the memory leak you have to make your baseRef var weak like this:
weak var baseRef: Base?

Related

Swift Reference Cycle When Capturing A Computed String Property Declared From Inside An Instance Method

I'm implementing an in-game store using Swift and SpriteKit. There is a class called Store which has a method setupItems() inside of which we declare and instantiate instances of a class StoreItem and also add each store item instance as a child of Store. Each StoreItem has an optional closure property called updateInventory which is set inside of setupItems() as well. This is an optional closure because some items don't have a limited inventory.
Store also has an unowned instance property storeDelegate which is responsible for determining how funds are deducted and how storeItems are applied once purchased. storeDelegate is unowned as it has an equal or greater lifetime than Store.
Now, here is where things get interesting - the closure updateInventory references a computed string variable called itemText which makes a calculation based on a property of storeDelegate. If itemText is declared and instantiated as a variable inside of setupItems() we have a reference cycle and store is not deallocated. If instead, itemText is declared and instantiated as an instance property of Store (right under the property unowned storeDelegate that it references) then there is no reference cycle and everything deallocates when it should.
This seems to imply that referencing storeDelegate from a computed variable inside an instance method of a class doesn't respect the unowned qualifier. Code examples follow:
Current Scenario
protocol StoreDelegate: AnyObject {
func subtractFunds(byValue value: Int)
func addInventoryItem(item: InventoryItem) throws
var player: Player! { get }
}
class Store: SKSpriteNode, StoreItemDelegate {
unowned var storeDelegate: StoreDelegate
init(storeDelegate: StoreDelegate) {
self.storeDelegate = storeDelegate
setupItems()
...
}
func setupItems() {
var itemText: String {
return "item info goes here \(storeDelegate.player.health)"
}
let storeItem = StoreItem(name: "coolItem")
storeItem.updateInventory = {
[unowned storeItem, unowned self] in
// some logic to check if the update is valid
guard self.storeDelegate.player.canUpdate() else {
return
}
storeItem.label.text = itemText
}
}
The above leads to a reference cycle, interestingly if we move
var itemText: String {
return "item info goes here \(storeDelegate.player.health)"
}
outside of updateItems and make it an instance variable of Store right below unowned var storeDelegate: StoreDelegate, then there is no reference cycle.
I have no idea why this would be the case and don't see mention of it in the docs. Any suggestions would be appreciated and let me know if you'd like any additional details.
storeItem.updateInventory now keeps strong reference to itemText.
I think the issue is that itemText holds a strong reference to self implicitly in order to access storeDelegate, instead of keeping a reference to storeDelegate. Anothe option is that even though self is keeping the delegate as unowned, once you pass ot to itemText for keeping, it is managed (ie, strong reference again).
Either way, you can guarantee not keeping strong reference changing itemText to a function and pass the delegate directly:
func setupItems() {
func itemText(with delegate: StoreDelegate) -> String
return "item info goes here \(storeDelegate.player.health)"
}
let storeItem...
storeItem.updateInventory = {
// ...
storeItem.label.text = itemText(with self.storeDelegate)
}
}

Swift: Init() Pattern for Parent/Child Relationship

Setup
Suppose I have two classes:
final class Parent: NSObject
{
var child: Child
}
final class Child: NSObject
{
weak var parent: Parent?
init(parent: Parent)
{
self.parent = parent
}
}
Question:
Now suppose that I want to instantiate a child and establish this relationship in the init() method of Parent. I would do this:
final class Parent: NSObject
{
var child: Child
init()
{
child = Child.init(parent: self) // ERROR!
}
}
Swift whines that I'm using self before super.init(). If I place super.init() before I instantiate child, Swift whines that child isn't assigned a value at the super.init() call.
I've been shutting Swift up by using implicitly-unwrapped optionals, like this:
final class Parent: NSObject
{
var child: Child!
init()
{
super.init()
child.init(parent: self)
}
}
My question is: What do people do in this situation? This is/was a VERY common pattern in Objective-C and Swift produces nothing but headaches. I understand that I could de-couple the assignment of parent from Child's init() so that I could init() child, call super.init(), and then assign parent, but that is not an option in the real-world cases where I run into this. It's also ugly and bloated.
I do realize Swift's intent is to prevent use of an object before it is fully initialized. And that it's possible for child's init() to call back to parent and access state that isn't set up yet, which becomes a danger with the implicitly-unwrapped optional approach.
I cannot find any guidance about Swift best practice here, so I'm asking how people resolve this chicken-and-egg issue. Is turning properties into implicitly unwrapped optionals really the best way around this limitation? Thanks.
You can make it lazy and all your headaches will gone!
final class Parent {
lazy var child = Child(parent: self)
}
final class Child {
weak var parent: Parent?
init(parent: Parent) {
self.parent = parent
}
}
In Swift, all stored properties should be initialized before self is available. Including stored properties in the superclass. So Xcode doesn't let you use self till then. But using lazy means that it is initialized before. So you can use self freely.
Some helpful notes:
Don't inherit from NSObject if you don't need objc advanced features for your class.
In swift naming convention, open parentheses ( will read as with in objective-C. So you don't need withParent as a label in your initializer.
Use internal and external naming of arguments as the convention suggests.
Also note that some of the above notes are written before comments

Memory access conflict with structs and observer pattern

I'm implementing an Observer design pattern on a Struct model object. The idea is that I will pass my model down a chain of UIViewController and as each controller modifies it, previous controllers will also be updated with changes to the object.
I'm aware this problem could be solved by using a class instead of struct and modifying the object directly through reference, however I'm trying to learn more about using structs.
struct ModelObject {
var data: Int = 0 {
didSet {
self.notify()
}
}
private var observers = [ModelObserver]()
mutating func attachObserver(_ observer: ModelObserver){
self.observers.append(observer)
}
private func notify(){
for observer in observers {
observer.modelUpdated(self)
}
}
}
protocol ModelObserver {
var observerID: Int { get }
func modelUpdated(_ model: ModelObject)
}
class MyViewController : UIViewController, ModelObserver {
var observerID: Int = 1
var model = ModelObject()
override func viewDidLoad() {
self.model.attachObserver(self)
self.model.data = 777
}
func modelUpdated(_ model: ModelObject) {
print("received updated model")
self.model = model //<-- problem code
}
}
Simply put, my model object notifies any observer when data changes by calling notify().
My problem right now is memory access: when data gets set to 777, self.model becomes exclusively accessed, and when it calls notify which calls modelUpdated and eventually self.model = model, we get an error:
Simultaneous accesses to 0x7fd8ee401168, but modification requires exclusive access.
How can I solve this memory access issue?
If you're observing "a thing," then that "thing" has an identity. It's a particular thing that you're observing. You can't observe the number 4. It's a value; it has no identity. Every 4 is the same as every other 4. Structs are values. They have no identity. You should not try to observe them any more than you'd try to observe an Int (Int is in fact a struct in Swift).
Every time you pass a struct to a function, a copy of that struct is made. So when you say self.model = model, you're saying "make a copy of model, and assign it to this property." But you're still in an exclusive access block because every time you modify a struct, that also makes a copy.
If you mean to observe ModelObject, then ModelObject should be a reference type, a class. Then you can talk about "this particular ModelObject" rather than "a ModelObject that contains these values, and is indistinguishable from any other ModelObject which contains the same values."

Swift Memory Management for Recursive Protocols

Consider the following Class in swift that maintains a recursive relationship with itself
class OctupPromisable {
var promise: OctupPromisable?
weak var chainedPromise: OctupPromisable?
func then(octupPromisable: OctupPromisable) -> OctupPromisable? {
self.promise = octupPromisable
octupPromisable.chainedPromise = self
return self.promise
}
func start() {
if nil == self.chainedPromise {
self.fire(nil)
}else {
self.chainedPromise!.start()
}
}
}
used as such:
OctupPromisable()
.then(OctupPromisable())
.then(OctupPromisable())
.start()
when I call start with the chainedPromise being weak, it always results in the chainedPromise being nil and hence the start method never recurses.
Making the chainedPromise strong, causes the start method to recurse and work correctly. But in doing so am I not creating a strong cyclic relationship that leads to memory leak? If so, what can be done in order to achieve the recursion and yet avoid memory leak?
Thanks!
Make your chained process strong, but after you've used it, set it to nil. You're done with it, so you don't need to hold a strong reference any more. If there are no other strong references, the object will be deallocated.
If you don't need to keep references after execution, you could use a strong reference and release inner promises recursively, so when your first promise deallocate, it will not cause a memory leak.
I couldn't test the code but it goes like this:
class OctupPromisable {
weak var promise: OctupPromisable? // Make it weak to avoid reference cycle
var chainedPromise: OctupPromisable? // Make it a strong reference
func start() {
if nil == self.chainedPromise {
self.fire(nil)
} else {
self.chainedPromise!.start()
self.chainedPromise = nil // Will be deallocated after all 'start' calls
}
}
}

Weak reference to closure in Swift

I have the following code to create an observable property for data binding. It's in the works so I'm not sure what the final implementation is going to be and I'm still pretty new to Swift.
class Observable<T> {
typealias Observer = T -> Void
var value: T {
didSet {
for observer in self.observers {
observer?(self.value)
}
}
}
var observers: [Observer?] = []
init(_ val: T) {
self.value = val
}
}
I would like to keep weak references to the Observer closures. I don't want to rely on the client to ensure that the closure is weak/unowned before passing it in, via the capture list. Especially because there can be many observable properties on a given class.
Is it possible to make the closure references weak in my Observable class?
UPDATE:
I found a couple of resources that I think will help me accomplish what I want:
Make self weak in methods in Swift
specifically,
func methodPointer<T: AnyObject>(obj: T, method: (T) -> () -> Void) -> (() -> Void) {
return { [unowned obj] in method(obj)() }
}
The following link refers to the above stackoverflow answer and goes into some more detail:
http://blog.xebia.com/2014/10/09/function-references-in-swift-and-retain-cycles/
and this is a two-way binding example:
http://five.agency/solving-the-binding-problem-with-swift/
specifically,
class BondBox<T> {
weak var bond: Bond<T>?
init(_ b: Bond<T>) { bond = b }
}
where the listener is wrapped in a class called Bond, which is weakly referenced in the BondBox.
Is it possible to make the closure references weak in my Observable class
No. Only class instances can be referred to via weak references in Swift, and a function is not a class instance. (And not only must they be class instances, they must be an Optional wrapping a class instance.)
There are some pretty obvious ways around this, or course - the simplest being a wrapper class. But I do not actually recommend that in this situation, because you have not convinced me that weak references to functions are needed here in the first place. Remember, a weak reference to an object to which there is no strong reference will instantly lose the reference and will be pointing at nil. I can't believe that is what you want. I think you're barking up a wrong tree here.
Weak/strong are for memory management of objects, so only apply for variables of reference types (i.e. types which point to objects). Function types in Swift are not reference types, and therefore it does not make sense to talk about weak/strong for their variables.
Plus, you do not actually have variables of function type in your code (except in the middle of the iteration). You simply have a variable of array type. Even in Objective-C, you can only mark variables as weak or strong, not values that are stored inside other things.
And if you were to write the thing you are writing in Objective-C, you would want the "Observable" to have strong references to the closures. Otherwise, who else would have a strong reference to the closure?