Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Struct Memory Leak

We're trying to use Swift structs where we can. We are also using RxSwift which has methods which take closures. When we have a struct that creates a closure that refers to self, that creates a strong reference cycle.

import Foundation import RxSwift  struct DoesItLeak {      var someState: String = "initial value"     var someVariable: Variable<String> = Variable("some stuff")      let bag = DisposeBag()      mutating func someFoo() {          someVariable.subscribeNext { person in              self.someState = "something"         }         .addDisposableTo(bag)     } } 

How do I know this? If I create 100,000 DoesItLeak objects and call someFoo() on each of them, I believe I have 100,000 objects with strong reference cycles. In other words, when I get rid of the DoesItLeak array containing those objects, the objects stay in memory. If I do not call someFoo(), there is no problem.

Variable is a class. So, I can see this memory issue by using xcode's Instruments' Allocations and filtering in Variable< String >

Filtering By Variable

enter image description here

If I try to use [weak self] such as in the following, I get a compiler error:

someVariable.subscribeNext { [weak self] person in 

The compiler error is "weak cannot be applied to non-class type"

In real/non-example code, we access methods and variables via self and it's a memory issue.

How can I resolve this memory issue while keeping the DoesItLeak a struct?

Thanks for your help.

like image 824
finneycanhelp Avatar asked Dec 21 '15 23:12

finneycanhelp


People also ask

What causes memory leaks in Swift?

A memory leak occurs when allocated memory becomes unreachable and the app can't deallocate it. Allowing an allocated-memory pointer to go out of scope without freeing the memory can cause a memory leak. A retain cycle in your app's object graph can also cause a memory leak.

Can Struct Cause retain cycle?

Sometimes structs and enums can be treated as reference types, and this means that retain cycles can occur in structs and enums too.

Can we use weak in struct in Swift?

Swift lets you mark var s in structs as weak , just like in classes. Currently this is the only way to have a collection of weak values without having one class instance per weak ref. But you have to manually filter such a collection; it doesn't auto-shrink when a reference goes away.


1 Answers

As Darren put it in the comments: "DoesItLeak can't be a struct" We cannot have the DoesItLeak be a struct and safely resolve the strong reference cycle issue.

Value types like structs exist on the stack frame. Closures and classes are reference types.

As the Strong Reference Cycles for Closures section puts it:

This strong reference cycle occurs because closures, like classes, are reference types.

Since the struct has the Variable class and the closure referring to self is stored into the Variable class using subscribeNext, it creates the strong reference cycle. See "Resolving Strong Reference Cycles for Closures" in Automatic Reference Counting Apple documentation.

like image 152
finneycanhelp Avatar answered Sep 29 '22 12:09

finneycanhelp