Closure outlives its created instance - swift

Let's say I have a view controller, and in its viewDidLoad I am calling this function:
func callDataSource()
{
let dataSource = DataSource()
dataSource.callUber {
print("In viewDidLoad")
}
return
}
and this DataSource class is
class DataSource {
func callUber(withSuccess success: #escaping (() -> Void))
{
let uberManager = UberDataFetcher()
uberManager.getPrice {
print("In Data Source")
success()
}
return
}
}
And this UberDataFetcher is just a class that calls an Uber API. My question is: I have defined the DataSource object within the scope of the callDataSource function; this means that the object gets deallocated once that function returns. How does the completion block outlives the instance that has created it?

#escaping marks the closure as possibly outliving the context that created it. A closure is an object that has associated state (ie your capture list) along with a reference tot he function. Your Datasource retains the closure so it stays alive at least as long as the Datasource hangs on to it. Not that this might be a problem if your closure retained self, because then self would also last for at least as long as the closure lasts, which is as long as Datasource holds on to it.

The closure is an object for purposes of memory management. Referring to it in the UberDataFetcher's callback means that it is retained by that closure. So it is kept alive, along with anything that it captures, until the end of that scope.
let uberManager = UberDataFetcher()
uberManager.getPrice {
print("In Data Source")
success() // <--- Captured
} // <--- End of scope

Related

Capture a method weakly

Note: This question is basically the same as this one, but for Swift 4 or 5.
Say I have a class that captures a closure:
class CallbackHolder {
typealias Callback = (String) -> Void
var callback: Callback
init(_ callback: #escaping Callback) {
self.callback = callback
}
func useCallback() {
self.callback("Hi!")
}
}
This class simply holds a callback in a variable, and has a function that uses that callback.
Now, say I have a client class that owns such a callback holder. This class wants the callback holder to call one of its methods as the callback:
class Client {
func callback(string: String) {
print(string)
}
lazy var callbackOwner = CallbackOwner(callback: callback)
deinit {
print("deinit")
}
}
This class has a callback, a callback owner that calls that callback, and a deinit that prints something so that we know whether we have a retain cycle (no deinit = retain cycle).
We can test our setup with the following test function:
func test() {
Client().callbackOwner.useCallback()
}
We want the test function to print both Hi! and deinit, so that we know that the callback works, and that the client does not suffer from a retain cycle.
The above Client implementation does in fact have a retain cycle -- passing the callback method to the callback owner causes the owner to retain the client strongly, causing a cycle.
Of course, we can fix the cycle by replacing
lazy var callbackOwner = CallbackOwner(callback: callback)
with
lazy var callbackOwner = CallbackOwner(callback: { [weak self] in
self?.callback($0)
})
This works, but:
it is tedious (compare the amount of code we now need)
it is dangerous (every new client of my CallbackOwner class must remember to do it this way, even though the original way is completely valid syntax, otherwise they will get a retain cycle)
So I am looking for a better way. I would like to capture the callback weakly at the CallbackOwner, not at the client. That way, new clients don't have to be aware of the danger of the retain cycle, and they can use my CallbackOwner in the most intuitive way possible.
So I tried to change CallbackOwner's callback property to
weak var callback: Callback?
but of course, Swift only allows us to capture class types weakly, not closures or methods.
At the time when this answer was written, there did not seem to be a way to do achieve what I'm looking for, but that was over 4 years ago. Has there been any developments in recent Swift versions that would allow me to pass a method to a closure-capturing object without causing a retain cycle?
Well one obvious way to do this would be to not hold a reference to CallbackHolder in Client i.e.
class Client {
func callback(string: String) {
print(string)
}
var callbackOwner: CallbackHolder { return CallbackHolder(callback) }
deinit {
print("deinit")
}
}
In the above case, I'd probably make CallbackHolder a struct rather than a class.
Personally, I don't see any value in wrapping the callback in a class at all. Just pass the callback around, or even Client. Maybe make a protocol for it to adhere to
protocol Callbackable
{
func callback(string: String)
}
extension Callbackable
{
func useCallback() {
self.callback(string: "Hi!")
}
}
class Client: Callbackable {
func callback(string: String) {
print(string)
}
deinit {
print("deinit")
}
}
func test(thing: Callbackable) {
thing.useCallback()
}
test(thing: Client())

What's the difference between the two closure

I tried comment and uncomment the activity() in the following code. I found when I commented the activity() the result in playground would just show "play tennis" once. However it would show twice if I uncommented activity(). What's the difference between the two statements?
class Baby {
var name = "peter"
var favoriteActivity: (() -> ())!
func outsideActivity(activity: #escaping () -> ()) {
//activity()
favoriteActivity = activity
}
}
var cuteBaby = Baby()
cuteBaby.outsideActivity {
print("play tennis")
}
cuteBaby.favoriteActivity()
This is what’s going on:
Consider this method:
func outsideActivity(activity: #escaping () -> ()) {
//activity()
favoriteActivity = activity
}
All that does is save the closure in the favoriteActivity property
Thus, when you do:
// create `Baby` instance
var cuteBaby = Baby()
// this method saves closure in `favoriteActivity`, but doesn’t call it
cuteBaby.outsideActivity {
print("play tennis")
}
// this now calls the closure
cuteBaby.favoriteActivity()
All the outsideActivity method does is save the closure in a property called favoriteActivity.
Thus you see one print statement.
However, now consider this method:
func outsideActivity(activity: #escaping () -> ()) {
activity()
favoriteActivity = activity
}
This actually calls the closure before saving it in the property.
So, when you do:
// create `Baby` instance
var cuteBaby = Baby()
// this method both calls the closure and then also saves it in `favoriteActivity`
cuteBaby.outsideActivity {
print("play tennis")
}
// this now calls the saved closure a second time
cuteBaby.favoriteActivity()
In this case, you’ll see your print statement being called twice.
That’s why the first rendition calls the closure only once, whereas the second calls the closure twice.
Usually when you pass a closure to a method, you either (a) call the closure from within the method (perhaps in some completion handler or the like); or (b) save the closure in some property so you can call it later.
So, this second example is very unusual, where outsideActivity both calls the closure itself and saves that closure in some property so you can call it again later. You usually do one or the other, but not both.

"Closure cannot implicitly capture a mutating self parameter" - after updating to Swift 3 [duplicate]

I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.

Object resurrection when using C callbacks from Swift

I'm trying to access a C API from Swift that requires the use of C callbacks.
typedef struct {
void * info;
CFAllocatorRetainCallBack retain;
CFAllocatorReleaseCallBack release;
} CFuncContext;
typedef void (* CFuncCallback)(void * info);
CFuncRef CFuncCreate(CFuncCallback callback, CFuncContext * context);
void CFuncCall(CFuncRef cfunc);
void CFuncRelease(CFuncRef cfunc);
CFuncCreate stores the callback and context on the heap (using malloc), then calls the retain callback to retain the info pointer. CFuncCall simply invokes the callback for demonstration purposes, and CFuncRelease calls the release callback, then frees the memory.
In the Swift code I want to use a dedicated object for info that keeps a weak reference back to my main object. When the main object is deinited, CFuncRelease is called to also clean up the C API memory.
This way, even if the C API decides to perform some delayed callbacks from different run loops, it always has a valid info pointer until it decides to invoke the release callback when it is finally done. Just some defensive programming :)
The info object has this structure:
final class CInfo<T: AnyObject> {
/// This contains the pointer back to the main object.
weak private(set) var object: T?
init(_ object: T) {
self.object = object
}
/// This variable is used to hold a temporary strong
/// `self` reference while retainCount is not 0.
private var context: CInfo<T>?
/// Number of times that `retain` has been called
/// without a balancing `release`.
private var retainCount = 0 {
didSet {
if oldValue == 0 {
context = self
}
if retainCount == 0 {
context = nil
}
}
}
func retain() {
++retainCount
}
func release() {
--retainCount
}
}
My main object SwiftObj uses the C API.
final class SwiftObj {
typealias InfoType = CInfo<SwiftObj>
private lazy var info: InfoType = { InfoType(self) }()
private lazy var cFunc: CFuncRef = {
var context = CFuncContext(
info: &self.info,
retain: { UnsafePointer<InfoType>($0).memory.retain(); return $0 },
release: { UnsafePointer<InfoType>($0).memory.release() }
)
return CFuncCreate(
/* callback: */ cFuncCallback,
/* context: */ &context
)
}()
func call() {
CFuncCall(cFunc)
}
deinit {
CFuncRelease(cFunc)
}
init() {
call()
}
}
func cFuncCallback(info: UnsafeMutablePointer<Void>) {
print("==> callback from C")
}
In my testing code, I first allocate a SwiftObj via an IBAction. Then, I set the reference back to nil again via a second IBAction.
The automated cleanup code should now properly deinit the SwiftObj, and from there the C API should be notified that it should clean up its memory. Then, the release callback on the info pointer should be invoked, which results in the info pointer's reference count reaching zero, and also deallocating the info pointer.
However, the deinit theory doesn't seem to work out. After SwiftObj's final reference is removed, another reference is added back when the release callback closure is invoked, and another reference is re-added during the CInfo.release method (as observed using Instrument's Allocations tracker). Behaviour also depends on the timings - e.g. the number of log statements.
With a minimal sample like the one below, it crashes immediately in the initial release callback closure with either of these two messages depending on the timings - first one is more common, second one can be achieved by a fast space tab space if you are lucky. Maybe there's even more - as I said, in my full example if you put in enough log statements sometimes it prolongs the final cleanup of the SwiftObj enough so that you can see the actual resurrection happening.
EXC_BAD_ACCESS (code=1, address=0x0)
EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
Minimal example can be downloaded here:
https://scriptreactor.com/Resurrection.zip
Run, then hit the Start button, then hit the Stop button. Welcome to the nightmare.
Instruments' Allocations view can also be quite interesting.
Seems like a compiler bug. Workaround is to remove the lazy attribute of the info instance variable.
https://bugs.swift.org/browse/SR-74

Swift Completion Block

I want to achieve the following :
In classB, to reload my database after adding 1 object. reloadDatabase() is called within the completionBlock.
In classB, reloadDatabase() will call getObjects() in classA to get the most updated list of database objects and pass to objectList in classB
Question: How do i ensure that whenever i call getObjectList() in classB, i will always get the most updated list? From my understanding, my objectList might not be update in reloadDatabase() block. I could be calling getObjectList() when reloadDatabase() haven't reach the completion block yet (objectList is still the old objectList).
I am pretty new to closures and blocks. Any guidance is greatly appreciated!
class classA: NSObject {
func addThisObject(object: RLMObject, completionBlock: () -> ())){
...
completionBlock()
}
func getObjects (completionBlock: ((list: [RLMObject]) -> ())){
var recordList = [RLMObject]()
...
completionBlock(list: recordList)
}
}
class classB: NSObject {
var objectList = [RLMObject]()
func addObject (object: RLMObject) {
classA().addThisObject(object, completionBlock: {() -> () in
self.reloadDatabase()
})
}
func reloadDatabase() {
classA().getObjects{(list) -> () in
self.objectList = list
}
}
func getObjectList() -> [RLMObject] {
return objectList
}
}
From your snippets it seems to me there is no asynchronous calls, so you won't be able to call getObjectList() before reloadDatabase() block. Closures are not asynchronous if you don't use them with something that is (e.g. GCD).
If you have asynchronous calls, but they are not in the snippets, then getObjectList() can be called while reloadDatabase() is being executed. Then you have few options:
Remove asynchronous calls
Use serial queue for your methods
Add boolean variable updateInProgress and check it in getObjectList() - how to do it
Ignore the fact that data may be outdated - it is correctness vs speed trade.
Let your database inform its clients that something changed
In your question, you don't say whether you'll be calling any of these functions from different threads. So when you call addObject() in classB, execution wouldn't even continue until the database has been reloaded and objectList was updated.
Using closures and blocks does not automatically imply that code will be executed on a different context.