简体   繁体   中英

Swift - Function as Variable with Self Reference

I've made a struct to hold data for my UITableViewCell s that looks like so:

struct CellData {
    var title: String
    var action: () -> Void
    init(title: String, action: () -> Void) {
        self.title = title
        self.action = action
    }
}

And in my TableViewController , I'm setting it up like this:

lazy var buttonCells: [CellData] = [
    CellData(
        title: "Button 1",
        action: {
            **self.doSomething()**
        }
    ),
    CellData(
        title: "Button 2",
        action: {
            **self.doSomethingElse()**
        }
    )
]

However, the use of self inside the action causes it so that the TableViewController isn't deinitialized when the controller is dismissed (the deinit function isn't called). When I remove the self references, and replace it with something else, the TableViewController is deinitialized just fine. How can I go about fixing this abandoned memory issue?

Change your action definitions to use a capture group:

action: {
  [weak self] in

  guard let strongSelf = self else {
    return
  }
  strongSelf.doSomething()
}

What the [weak self] capture group declaration does is to convert self to a weak variable inside the block. If the owning object gets deallocated while the block is waiting to be called it gets passed nil instead.

Then once inside the block the guard statement tries to map the weak self definition to a strong local variable. If self is nil, it exits. If not, strongSelf contains an unwrapped strong reference to self and you proceed as normal.

Strong Reference Cycle

Inside your table view controller you are probably creating CellData like this right?

CellData(title: "Hello") { 
    // here you are using self
}

Or maybe you are writing this

CellData(title: "Hello", action: {
    // here you are using self
})

In both case there's a problem because you are creating a Strong Reference Cycle .

Solution

you can avoid that using this code

CellData(title: "Hello") { [unowned self] in
    // here you can use self
}

Last thing

Just remove the init in your struct, Swift will provide it for you ;)

struct CellData {
    let title: String
    let action: () -> ()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM