Strong reference cycle for closures in Swift - swift

I was going through the documentation (chapter on “Automatic Reference Counting” section “Strong Reference Cycles for Closures”) and I can't seem to figure out cases, when defining a class, in which I should keep a strong reference to self (the instance of that class) in a closure to a property.
Capture Lists seem always the best solution to avoid memory leaks, and I really can't think of any scenarios in which I should keep a strong reference cycle.
Here are the examples that the documentation gives:
class HTMLElement {
let name: String
let text: String?
// Without Capture List
#lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
class HTMLElement {
let name: String
let text: String?
// With Capture List
#lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}

You need to keep a strong reference to self if you’re creating a closure to be executed by an object or function whose lifetime may not match self’s.
For example:
class A {
func do() {
dispatch_async(dispatch_get_global_queue(0, 0)) {
println("I printed \(self) some time in the future.")
}
}
}
var a : A? = A()
a.do()
a = nil // <<<
At the arrow the main function body will release its last reference to the newly created instance of A, but the dispatch queue needs to keep a hold on it until the closure is done executing.

Related

Is it possible to exclude certain property (Like class type) from being copied during struct copy?

I have the following struct, which contains class.
import Foundation
func generateRichText(body: String?) -> NSMutableAttributedString? {
if body == nil {
return nil
}
// TODO: Some complex logic to decorate body string will be added soon...
let myAttrString = NSMutableAttributedString(string: body!)
return myAttrString
}
struct Note {
var body: String?
// Technique described in https://stackoverflow.com/a/25073176/72437
var bodyAsRichText: NSMutableAttributedString? {
mutating get {
if (cachedBodyAsRichText == nil) {
cachedBodyAsRichText = generateRichText(body: body)
}
return cachedBodyAsRichText
}
}
// TODO: This is a class. I don't want it to be copied over during struct copy.
// If it is copied during struct copy, both struct will be sharing the same
// class instance.
private var cachedBodyAsRichText: NSMutableAttributedString?
}
var note = Note()
note.body = "hello"
print("note.bodyAsRichText = \(Unmanaged.passUnretained(note.bodyAsRichText!).toOpaque())")
var note_copy = note
print("note_copy.bodyAsRichText = \(Unmanaged.passUnretained(note_copy.bodyAsRichText!).toOpaque())")
For the above code, the output will be
note.bodyAsRichText = 0x000055c035cfce70
note_copy.bodyAsRichText = 0x000055c035cfce70
What my desired output is, different struct instance, should be having their very own class instance (cachedBodyAsRichText)
Hence, is there a way, to exclude cachedBodyAsRichText from being copied over, during struct copy?
Your solution is incomplete. Here is a complete and correct solution.
struct Note {
var body: String = "" {
didSet {
cachedBodyAsRichText = nil
}
}
var bodyAsRichText: NSAttributedString {
mutating get {
if (cachedBodyAsRichText == nil) {
cachedBodyAsRichText = generateRichText(body: body)
}
return cachedBodyAsRichText!.copy() as! NSAttributedString
}
}
private var cachedBodyAsRichText: NSAttributedString? = nil
}
You need to clear out the cache every time the body is modified. Once you do that, it won't matter if the object is shared among structs.

lazy instantiation closures vs. just using methods

I was following a Swift tutorial on closures and ran across this piece of code.
class HTMLEelement {
let name: String
let text: String
lazy var asHTML: () -> String = {
[weak self] in
guard let this = self else { return "" }
return "<\(this.name)> \(this.text) </\(this.name)>"
}
init(name:String, text: String) {
self.name = name
self.text = text
}
deinit {
print("HTMLELEMENT \(name) is being deallocated")
}
}
Why did they define the function asHTML like they did instead of just using a regular public method?
Without declaring var as lazy, you cannot use "self" during its initialization. I think this was the main reason to use lazy in your example.

deinitialization, self, and closures. [duplicate]

This question already has answers here:
Different closures giving different results for retain cycles in swift
(2 answers)
Closed 5 years ago.
Now when a closure refers to self within its body the closure captures self, which means that it holds a strong reference back to the HTMLElement instance(see below). A strong reference cycle is created between the two. This means that the instance won't deinitialize (as shown below); however when I tried to replace self with heading (the instance) deinitilization did work which means that a strong reference cycle didn't exist. My understanding is that heading in this case is the same as self, since self is the instance itself. So why did the instance deinitialize when I replaced it with the instance 'heading'?
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
let defaultText = "some default text"
return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var heading = HTMLElement(name: "h1")
let defaultText = "some default text"
print(heading.asHTML())
// Prints "<h1>some default text</h1>”
heading = HTMLElement(name: "h4")
output:
< h1 > some default text < /h1 >
h1 is being deinitialized
Now if the closure was replaced as follows:
lazy var asHTML: () -> String = {
let defaultText = "some default text"
return "<\(self.name)>\(self.text ?? defaultText)</\(self.name)>"
}
the output would be:
< h1 > some default text < /h1 >
The correct way to avoid strong reference cycle with closure is to mark self as either unowned or weak, e.g.
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { [unowned self] in
let defaultText = "some default text"
return "<\(self.name)>\(self.text ?? defaultText)</\(self.name)>"
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
It begs the question why you don't just use a function
func asHTML() -> String {
let defaultText = "some default text"
return "<\(name)>\(text ?? defaultText)</\(name)>"
}
or computed property:
var asHTML: String {
let defaultText = "some default text"
return "<\(name)>\(text ?? defaultText)</\(name)>"
}

Save struct in background mutating function

I'm trying to save a struct in background but I get this error :
closure cannot implicitly capture a mutating self parameter
This is my code :
//MARK: Parse self methods
fileprivate mutating func ParseSave(_ completionBlock: #escaping SuccessCompletionBlock) {
let message: PFObject = PFObject(className: "Message")
if let id = self.id {
//this object exit just update it
message.objectId = id
}
// set attributes
if let text = self.text {
message["text"] = text
}
message["sender"] = PFUser(withoutDataWithObjectId: self.sender.id)
message["conversation"] = PFObject(withoutDataWithClassName: "Conversation", objectId: conversationId)
message["viewed"] = self.viewed
message.saveInBackground { (success, error) in
if success {
// the next 3 lines cause the error : (when I try to update the struct - self )
self.id = message.objectId
self.createdAt = message.createdAt ?? self.createdAt
self.updatedAt = message.updatedAt ?? self.updatedAt
}
completionBlock(success, error)
}
}
I've checked those question: 1 - 2 I've added the #escaping
but didn't work.
I think it will help if we minimally elicit the error message you're getting. (For delay, see dispatch_after - GCD in swift?.)
struct S {
var name = ""
mutating func test() {
delay(1) {
self.name = "Matt" // Error: Closure cannot ...
// ... implicitly capture a mutating self parameter
}
}
}
The reason lies in the peculiar nature of struct (and enum) mutation: namely, it doesn't really exist. When you set a property of a struct, what you're really doing is copying the struct instance and replacing it with another. That is why only a var-referenced struct instance can be mutated: the reference must be replaceable in order for the instance to be mutable.
Now we can see what's wrong with our code. Obviously it is legal for a mutating method to mutate self; that is what mutating means. But in this case we are offering to go away for a while and then suddenly reappear on the scene (after 1 second, in this case) and now mutate self. So we are going to maintain a copy of self until some disconnected moment in the future, when self will suddenly be somehow replaced. That is incoherent, not least because who knows how the original self may have been mutated in the meantime, rendering our copy imperfect; and the compiler prevents it.
The same issue does not arise with a nonescaping closure:
func f(_ f:()->()) {}
struct S {
var name = ""
mutating func test() {
f {
self.name = "Matt" // fine
}
}
}
That's because the closure is nonescaping; it is executed now, so the incoherency about what will happen in the future is absent. This is an important difference between escaping and nonescaping closures, and is one of the reasons why they are differentiated.
Also, the same issue does not arise with a class:
class C {
var name = ""
func test() {
delay(1) {
self.name = "Matt" // fine
}
}
}
That's because the class instance is captured by reference in the closure, and a class instance is mutable in place.
(See also my little essay here: https://stackoverflow.com/a/27366050/341994.)

Swift: Weak referenced stored & nested blocks / closures

I'm looking to nest a block / closure whilst another process completes off of the main thread like so
typealias FirstBlock = (jsonDictionary:NSDictionary?,errorCode:NSString?) -> Void
typealias SecondBlock = (complete:Bool?,errorCode:NSString?,dictionary:NSDictionary?) -> Void
Controller
func startPoint {
SomeNetworkManager.sharedInstance.firstProcess(self.someDictionary) { (complete, errorCode, dictionary) -> Void in
// I want to get here with a strong reference to these objects in this class only
print(complete,errorCode,dictionary)
}
}
SomeNetworkManager
func firstProcess(dictionary:NSDictionary?, completion:SecondBlock?) {
let request = HTTPRequest.init(requestWithPath:"path", httpMethod: .post) { (jsonDictionary, errorCode) -> Void in
let organisedDictionary:NSMutableDictionary = NSMutableDictionary()
// Some processing of the json into a new dictionary
dispatch_async(dispatch_get_main_queue()) {
if errorCode == nil {
completion!(complete:true,errorCode:nil,dictionary:organisedDictionary)
}
else {
completion!(complete:false,errorCode:errorCode,dictionary:nil)
}
}
}
request.postDataDictionary = refinementsDictionary as! NSMutableDictionary
request.request()
}
HTTPRequest
var processBlock:FirstBlock?
init(requestWithPath path:NSString, httpMethod method:HTTPMethod, andProcessBlock block:FirstBlock) {
super.init()
self.requestURL = NSURL(string:path as String);
self.responseData = NSMutableData()
self.processBlock = block
switch (method) {
case .post:
self.httpMethod = kPost
break;
case .put:
self.httpMethod = kPut
break;
default:
self.httpMethod = kGet
break;
}
}
// An NSURLConnection goes off, completes, I serialise the json and then...
func completeWithJSONDictionary(jsonDictionary:NSDictionary) {
self.processBlock!(jsonDictionary:jsonDictionary,errorCode:nil)
self.processBlock = nil
}
I'm missing something fundamental regarding ARC retain cycles because every time one of these is called I'm getting a memory leak.. I've had a look at
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
with no joy.. I think Defining a Capture List is the right area, but as for storing a block and how to define it I have no idea what I'm doing wrong.
In all likelihood, you're getting retain cycles because the completion block references the HttpRequest (probably via the calling object), references the completion block, something like:
class HttpReference {
let completion : ()->()
init(completion:()->()) {
self.completion = completion
}
}
class Owner {
var httpReference : HttpReference?
func someFunction() {
httpReference = HttpReference() {
print(self.httpReference)
}
}
}
There are two ways to break the cycle, either by using an unowned reference or a by using a weak reference, both are fairly similar, in this case, the norm would be to use an unowned reference to self by changing:
func someFunction() {
httpReference = HttpReference() { [unowned self] in
print(self.httpReference)
}
}
Now, self isn't retained, thus breaking the retain cycle.