Im confused on how can I manipulate the properties inside an instance when it gets deinitialized? - ios

I have this from either the Apple documentation or the swift book
When an instance gets deinitialized, you still have access to the
properties inside the instance and can manipulate them as needed
before the instance totally goes away.
I'm confused, do they mean when we for example do some mathematical action using the instances property in the deinit() method? or lets say when we print a property of type string that was part of a specific instance, also from the deinit() method?
If so, then is the deinit() method the only way to manipulate a property when it is being deinitialized?

if you have a swift class with a a var you know you have to clean up after because ARC can't free it (e.g. C memory), you can still do that in deinit. The pointers stored in the properties are still valid!
it isn't useful for much more though (ok end observing with the notification center or kvo) BECAUSE there is no guarantee WHEN deist is called. ONLY that it is called before deallocation [whenever that is]

deinit is called right before deallocation (when the retainCount reaches 0), so all your properties are still valid and you can print your string. You don't need to set properties to nil explicitly in deinit as that happens automatically.
This being said, most classes don't even need deinit implemented
Most of the time I used deinit to remove observer that the instance is registered to, post any notifications if needed, and things like that.

As far as I know, the deinit method gets called just before the instance gets deinitialized, to give you a final opportuninty to do whatever you need to do (cleanup, close a file, terminate a network connection, etc).
What the documentation says is that, at the time deinit is called your object has not been deinitialized yet (but will be very soon), so you still can (for the last time) access its properties.

Related

Why am I crashing when trying to create a weak reference to self while dealloc is happening on another thread?

Background
Our app has a class that attempts to implement the Receptionist Pattern for KVO observation. Other classes throughout the app (such as view controllers) create instances of this one Receptionist class to serve as the KVO observer. Each Receptionist instance keeps a copy of a block provided by the owner, which the Receptionist instance will invoke on the proper operation queue when a KVO notification arrives.
The Receptionist's dealloc method invokes the KVO removeObserver method. The Owner keeps the Receptionist instance as a strong-reference field, so when the Owner is deallocated, the Receptionist will remove itself as an observer in the process of being deallocated.
The Crash
We're seeing reports from the field of crashes when the KVO notification is received by a Receptionist instance on one thread while the same instance's dealloc is in progress on another thread. The Receptionist's implementation of observeValueForKeyPath:ofObject:change:context: is crashing on this line:
__weak typeof(self) weakSelf = self;
The stack trace in the crash report shows this as a call to objc_initWeak, which calls weak_register_no_lock, which calls _objc_fatal.
The object whose key is being observed by this particular Receptionist is never deallocated. The Owner is also not being deallocated; the Owner is replacing this Receptionist instance with a different one.
The Confusion
I can understand that it's not useful to create a weak reference to an object that's already being deallocated, but I would expect weakSelf to receive a nil value, not to cause a crash.
The documentation for objc_initWeak explicitly mentions setting the target to null if the argument to which the reference is desired has begun deallocation. That sounds like the desired behavior, but I don't think it's what I'm seeing. I'm not keen to replace that line with an explicit call to objc_initWeak, since I doubt I'd manage the deallocation properly.
Could it really be the Receptionist's responsibility to notice that its own deallocation is in progress before requesting a weak reference to self? I would assume that there's some window between when an NSObject's deallocation starts and when that object's dealloc method is called, so signalling within the object from the dealloc method sounds flaky.
Thank you for reading!
PS: heavily edited after reading the questions raised by Ken Thomases.
This has nothing to do with the creation of the weak reference. The line you cite should only be run in a context where something has a strong reference to self.
Think about it: the crash that you're seeing may be during that line within your observeValueForKeyPath:ofObject:change:context: implementation, but, since there's clearly a race between deallocation and the call of that method, the deallocation could also occur during dispatch of that method call (or some other point). You're vulnerable to different crashes. So, no changes to the implementation of the method could possibly fix the problem, since the problem could manifest before your method is even called.
It's your responsibility to keep a strong reference to an object if you're going to be calling methods on that object. Or, from the other perspective, to avoid calling methods on object pointers that you're not sure will live for the duration of the call (because you hold a strong reference or some other API guarantee).
With KVO, you need to remove observers before releasing your last strong reference.

Remove all observers from a class

In a project I have a class say "A", there are many other class that are observing class "A"'s property values.
Sometimes the class "A" instance gets deallocated and observees fails resulting in crash!
Is there any way to remove all the observers from class "A"? Something like this:
-(void) dealloc{
[remove allObservers forKey:#"theKey"];
}
In short, sadly no. KVO is made so that it gets you in the end, unfortunately.
I've struggled with this thing before, and I found the following two solutions:
Use a proxy method to register for observation in your observee, which will maintain a list of weak references to observers.
Ideally, you'd want a proxy method for removing observers as well, so that your list is updated accordingly (although, since they are weak references in your list, it wouldn't hurt if some observer removed itself using standard KVO instead of your proxy method, and then deallocd itself).
In case your observee gets deallocated, it should inform all observers (using a protocol), or just remove them outright itself. For the last one, using exceptions might come in handy as well (I am aware that exceptions are evil in Obj-C, but what to do):
#try
{
[self removeObserver:observee forKeyPath:#"path"];
}
#catch (NSException * __unused exception) {}
Use some abstraction from KVO. There are a couple of projects that come to mind such as RZDataBinding and MAKVONotificationCenter (despite it's name, it actually pertains to KVO)
You should keep "A" class alive until there are other objects observing its property values. Maybe it gets deallocated because you're not correctly handling its reference.
You should check if "A" needs a 'strong' reference. When you don't need "A" anymore (i.e.: you're popping a view controller, you are refreshing a table, you're clearing a scrollview), you should also remove any observer attached to it (and be able to do it).

Closures vs Delegate pattern

I'm working with network request classes and I'm concerned about crashes. For instance, working with closures is really easy as you pass a callback method to a function:
// some network client
func executeHttpRequest(#callback: (success: Bool) -> Void) {
// http request
callback(true)
}
// View Controller
func reload() {
networkClient.executeHttpRequest() { (success) -> Void in
self.myLabel.text = "it succeeded" // NOTE THIS CALL
}
}
However, since the process that should execute the callback is async, when callbacks interact with container class element (in this case an UIKit class) it may be vulnerable to crashes in situations like
The user navigated to another View Controller while the async task was still executing
The user pressed the home button while the async task was still executing
Etc...
So, when the callback finally gets fired, self.myLabel.text might result in a crash, as the View Controller to whom self was refering could already be deallocated.
Up to this point. Am I right or do swift implement something internally so that this never happens?
If I am right, then here's when the delegate pattern comes in handy, as delegate variables are weak references, which means, they are not kept in memory if deallocated.
// some network client
// NOTE this variable is an OPTIONAL and it's also a WEAK REFERENCE
weak var delegate: NetworkClientDelegate?
func executeHttpRequest() {
// http request
if let delegate = self.delegate {
delegate.callback(success: true)
}
}
Note how self.delegate, since it is a weak reference, it will point to nil if the View Controller (who implements the NetworkClientDelegate protocol) gets deallocated, and the callback is not called in that case.
My question would be: do closures have anything special that makes them a good choice in scenarios similar to this one, rather than going back to delegate pattern? It would be good if examples of closures (that won't end up in crashes due to nil pointer) are provided. Thanks.
So, when the callback finally gets fired, self.myLabel.text might result in a crash, as the View Controller to whom self was referring could already be deallocated.
If self has been imported into the closure as a strong reference, it is guaranteed that self will not be deallocated up until the closure has been finished executing. That is, the view controller is still alive when the closure gets called - even if it's view is not visible at this time. Statement self.myLabel.text = "it succeeded" will be executed, but even the label will not be visible, it will not crash.
There is, though, a subtle issue which can lead to a crash under certain circumstances:
Suppose, the closure has the last and only strong reference to the view controller. The closure finishes, and subsequently gets deallocated, which also releases the last strong reference to the view controller. This inevitable will call the dealloc method of the view controller. The dealloc method will execute on the same thread where the closure will be executed. Now, that the view controller is a UIKit object, it MUST be guaranteed that all methods send to this object will be executed on the main thread. So, IFF dealloc will be actually executed on some other thread, your code may crash.
A suitable approach would require to "cancel" an asynchronous task whose result is no longer needed by the view controller when it is "closed". This, of course, requires that your "task" can be cancelled.
To alleviate some issues with your former approach, you might capture a weak reference of your view controller instead of a strong reference when defining the closure. This would not prevent the asynchronous task to run up to its completion, but in the completion handler you can check whether the view controller is still alive, and just bail out if it does not exists anymore.
And, if you need to "keep" an UIKit object in some closure which may execute on some arbitrary thread, take care that this might be the last strong reference, and ensure this last strong reference gets released on the main thread.
See also: Using weak self in dispatch_async function
Edit:
My question would be: do closures have anything special that makes them a good choice in scenarios similar to this one, rather than going back to delegate pattern?
I would say, closures are the "better" approach in many use-cases:
Delegates are more prone to issues like circular references than closures (since they are "owned" by an object, and this object might be captured as a variable in the delegate).
The classic use-case for closure as completion handlers also improves the "locality" of your code making it more comprehensible: you state what shall happen when a task finished right after the statement invoking the task - no matter how long that may take.
The huge advantage with closures versus regular "functions" is that a closure captures the whole "context" at the time when it is defined. That is, it can refer to variables and "import" them into the closure at the time when it is defined - and use it when it executes, no matter when this happens, and when the original "stack" at definition-time is gone already.
If I were you I would use closures since they are more convenient and flexible than delegation in this scenario.
Regarding the user navigating to other view controllers and the async operation still executing in the background you could keep a reference to those operations and whenever the user navigates away from the view controller you could cancel them.
Alternatively, you could verify if the view controller's view is visible before updating the UI:
viewController.isViewLoaded && viewController.view.window
Regarding the app entering background/foreground, you could pause/resume the operations by overridng the applicationDidEnterBackground and applicationWillEnterForeground or registering for the appropriate notifications: UIApplicationWillEnterForegroundNotification / UIApplicationDidEnterBackgroundNotification
I highly recommend you to use AFNetworking since it's API offers all the things I mentioned above, and much more.

Swift : deinit is not calling on back button action

In objective -C on back button dealloc method gets called. Anything similar to that in swift ?
As you seem to understand, deinit is the equivalent of dealloc. If it's not being called, your object is not being destroyed, which means something has a strong reference to it. This is identical in ObjC and Swift. When you remove your last strong reference, deinit will be called.
Neither dealloc nor deinit has anything to do with a "back button action." They are only related to freeing objects, and should generally only perform resource cleanup. If you're relying on them being called in response to a user action, you probably have a design error.
From the Swift Documentation:
A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.
Typically you don’t need to perform manual clean-up when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional clean-up yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.

what happens if delegate doesnot exist anymore?

I came around a interesting issue while working on my app. Imagine the scenerio where
There exist one object, Lets call it A.
A, then creates an object(B) of some delegation based class, say NSURLConnection.
A assigned itself as delegate of B, provided A has implemented all the required delegate methods.
A asks B to start its processing. In our example i.e. fetching data from some server.
As soon as B finished fetching data, it will call some specified method of A.
In the last step, suppose while calling the methods of A, B finds that the A object doesnt exist anymore. Then what happens???
I'm not sure but does it cause crash?
If yes, then please suggest me how to avoid the situation.
In my case I assigned the viewcontroller as delegate of some object, say X in viewDidLoad method. There are cases when viewcontroller get destroyed before X calls the delegate methods defined in the viewcontroller.
If assigning X's delegate to nil solves the problem. Then where
should i do that.
In short, which method is called only once while unloading phase of view controller likewise
viewDidLoad in its loading phase.
The best way to achieve this kind of communication between classes (where class A could be deallocated at any time) is listening to NSNotifications.
As you stated , using weak(assign) delegates is dangerous and requires extra thought.
Using strong delegates could as well create a memory bloat (why should we retain a view controller so long after popping it from the view anyway?).
For more on NSNotificationCenter and notifications , you can find a lot of info in the SDK docs.. for specific questions, you know where to ask..
You should not reach a situation where one object holds a reference to another object which may be deallocated somewhere else without the owner object being notified.
Either when deallocating object A notify object B (by making member a nill in object B for example) or modify your design/flow to never allow A to be deallocated before B finishes (e.g. retain A when assigning as a delegate in B if possible)
Checking against a valid delegate object should be sufficient enough.
if (delegate)
[delegate method];

Resources