Last method to be called consistently in an iOS class? - ios

In an iOS class that will not appear as a view e.g.
#interface MyDataClass : NSObject{}
Is there a method that can be overridden and is consistently called at the end of the classes' execution/lifecycle similar to viewDidUnload or dealloc, that can call methods safely?
Alternatively how would one go about implementing a method that could recognise the completion of the useful lifespan of such a class?

I believe dealloc is the last method that's get called if an NSObject subclass is released from memory.
- (void)dealloc
{
[super dealloc];
}

like
- (void)dealloc
{
[super dealloc];
}
?

If you mean a method that runs at the end of lifetime of the Class as a whole (not an instance), I wonder how is the runtime supposed to know when you are done using a class (you can create new instances at any time)? There is an +initialize method, but technically the class itself is available forever (until the program exits).
If you mean the lifetime of an instance, the method you are looking for is -dealloc.
-dealloc is called whenever an object's internal reference count reaches zero. In non-ARC code, if you override it you must call the superclass' implementation, so that ultimately NSObject's -dealloc is called and that is when the memory is freed.
EDIT: Regarding low memory situations, this is how you register for notifications:
// Somewhere inside the -init method of your class
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMethod:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
Inside dealloc, you MUST do this:
[[NSNotificationCenter defaultCenter] removeObserver:self];
...otherwise, your app may crash.
And of course, you must implement a method with the following signature that will be called on low-memory situations:
- (void) myMethod:(NSNotification*) notification
{
// Do some cleanup here, perhaps.
}
(otherwise, your app will crash)

Let's imagine you want to have a different method, other than dealloc, called on low memory conditions (not when the object is deallocated). Which object would call that method?
viewDidUnload is part of the UI Framework and it is called by it. When the application gets a message about low memory conditions, the framework just redirects the message to all active view controllers.
You can implement the same by creating a method on your custom class, e.g. -(void)onLowMemory and then call it from you application delegate from applicationDidReceiveMemoryWarning method or you can register the class to listen to UIApplicationDidReceiveMemoryWarningNotification.

This stackoverflow link more or less answers my question, but not entirely. I think my question has more to do with architecture or method procurement and procedure as opposed to something that can be answered simply.

Related

Observe and remove an NSNotification within a category before dealloc

I am currently observing a notification throughout the life of an object in a category. However, I am swizzling the dealloc method to have a spot to remove the observation. This feels bad and I am uncomfortable with it, additionally I am running into problems.
Does anyone have any ideas how I can stop observing the notification just before the object will be deallocated within a category?
The best way to run code at the deallocation of an object for which you can't override dealloc is by using associated objects.
The object that you associate to will release its strongly-held associated objects when it deallocates. As long as that is the only owner, the associated object's dealloc will then be called. Using a class you control for the associated object, that's your entry point.
I've got a demonstration of using this trick to deregister for KVO in a GitHub repo https://github.com/woolsweater/UIViewController-WSSDataBindings
The controller associates a helper object to itself:
- (void)WSSBind:(NSString *)bindingName
toObject:(id)target
withKeyPath:(NSString *)path
{
WSSBinding * binding = [WSSBinding bindingWithBoundName:bindingName
onObject:self
toKeyPath:path
ofObject:target];
// Attach the binding to both target and controller, but only make it
// owned by the target. This provides automatic deregistration when the
// target is destroyed, and allows the controller to unbind at will.
// Disregard the target and bound path for the key to allow mirroring
// Cocoa's unbind: method; this is simplest for the controller.
NSUInteger key = [self WSSAssociateKeyForBinding:bindingName];
objc_setAssociatedObject(target, (void *)key, binding,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self, (void *)key, binding,
OBJC_ASSOCIATION_ASSIGN);
}
And the WSSBinding class implements dealloc to remove the observer that's been set up elsewhere. You can do the same for your NSNotification registration.

Proper memory management when invoking a delegate callback that may cause object to be released

I'm trying to figure out the best practice for memory management around invoking a delegate callback.
One issue I had seen in the past is that invoking a delegate callback may cause the object to be deallocated before returning, which may cause it to crash if the object tries to access its own properties after invoking the callback.
For example, an object (e.g. A) may do something like this:
- (void)doStuff
{
[_delegate done];
NSLog(#"msg = %#", _msg);
}
If invoking done leads to A getting deallocated, the subsequent attempt to access _msg will result in a BAD_ACCESS crash.
It is possible to get around this by, say, delaying the invocation of done till the next run loop (e.g. by doing a dispatch_async), but that would force us to have to make it asynchronous. Alternatively, we can retain self prior to calling done and releasing right after, but that just seems like a hacky workaround as well. Does any one have a recommended style for dealing with this issue?
I'm not sure this question really has anything to do with 'delegates' to be honest but more just memory management in general.
If you're not finished with an object make sure you are still 'retaining' it. When you're finished with it 'release' it and don't access it any further.
Also try and move to ARC if possible and life becomes much easier! :)
It's crashing because the delegate you want to call refers to a deallocated object.To fix this crash you need to set Delegate = nil; in your dealloc method.
You can not set property of delegate as retain as it will cause issue in memory management.
It shouldn't be possible, that the delegate method releases the sender. What let you run in this situation?
It is always possible to pair +1 with -1 methods in one (C) block.
If you work with MRC:
Anyway, I would prefer a retain + autorelease on sender in the delegate method before causing the deallocation over a retain + release in the delegate. Therefore the sender should be added as a parameter to the delegate method as usual:
- (void)senderIsDone:(Sender*)sender
{
[[sender retain] autorelease];
…
[sender release]; // Something like this in your code
}
But at all: This should not happen.
Another strategy is to delay that code that causes the deallocation. In the example above
- (void)senderIsDone:(Sender*)sender
{
[sender performSelectorOnMainThread:#selector( release ) withObject:nil waitUntilDone:NO]; // Whatever make the sender disappear
}

iOS: How to handle a released delegate

I have a object that serves as a connection layer between my view controller and my webservice. This object takes a delegate and informs that delegate whenever data is returned from the server. I am running into a problem where the delegate gets dealloc'd while an http request is running. When the request returns, my object attempts to call a method on the delegate and the app crashes.
What is the best way to handle this. I have read in several places that you should not retain your delegates because very frequently they are retaining the object too, resulting in a cyclic dependence. So if I can't retain my delegate, how do I check if it has been dealloc'd before I call methods on it?
#property (nonatomic, assign) NSObject<ServerConnectionDelegate>* delegate;
Usually you should use delegate pattern if life-time of the delegate is longer than lifetime of worker object. (sorry not sure about correct term here).
You have several options how to fix that:
As a workaround you can set connection delegate to nil in your object's dealloc method.
If data is required (may be for some later usage) you can use NSNotification to inform delegate for any connection events instead of delegate pattern.
As Jack suggested in his comment you can make your delegate a weak property of connection - that will probably be the best solution if your project is using ARC
You should cancel any running request and set it's delegate to nil in dealloc method.
- (void)dealloc
{
[yourWebServiceRequest cancelRequestAndClearDelegate];
[super dealloc];
}

AVFoundation IOS: playing Background Music [duplicate]

i have an NSNotificationCenter selector,
where to put it ? in the delegate (if yes then where?) in the controller?
where to put the method as well.
do i need to dealloc the NSNotificationCenter ?
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceNotificationReceived:) name:UIApplicationDidBecomeActiveNotification object:nil];
- (void)deviceNotificationReceived:(NSNotification *)notification
{
[self.soundMgr endInterruption];
}
The deviceNotificationReceived: method must be an instance method of the argument to addObserver:. It is self in this instance, so your method should go in the same class.
You should not release the NotificationCenter, as you did not create or retain it.
Your question was a little hard to understand, is this what you were asking?
Hi, i have an NSNotificationCenter selector,
okay, you mean you have a selector for a method in NSNotificationCenter.
In Objective-C, “selector” has two
meanings. It can be used to refer
simply to the name of a method when
it’s used in a source-code message to
an object. It also, though, refers to
the unique identifier that replaces
the name when the source code is
compiled.
http://developer.apple.com/mac/library/documentation/cocoa/....../ocSelectors.html
So you have created a selector that refer to a method.
where to put it ?
It's a variable, you can store it where ever you feel it fits in your design.
in the delegate
See above.
(if yes then where?)
It's a variable, it depends on your usage.
in the controller?
Do you have controller? Depends on your design.
where to put the method as well.
Which method?
do i need to dealloc the NSNotificationCenter ?
No, [NSNotificationCenter defaultCenter] returns a reference to the notification center, you don't dealloc it.
Since you are subscribing to the UIApplicationDidBecomeActiveNotification notification, the most logical place to put the notification is in the applicationdDidFinishLaunching method of your app delegate.
That's the first point your code gets called, so you cannot set it earlier.
where to put it ?
It depend on when you need to register for notification. One way is to add observer in 'init' method of the class and remove notification in 'dealloc'method of the class.

Removing all notification observer from a single place

I want to remove a notification observer and I am using the method:
[[NSNotificationCenter defaultCenter] removeObserver: name:#"myNotification" object:nil];
for this. Now there are many observers who are listening to this notification and I want to remove all of them in one shot from a centralised place. Can I pass 'nil' in first parameter and it will remove all observers who are listening to myNotification?
You can remove an object from the notification center all together which means no notifications will get triggered. For example, when I have a view controller that has registered for notifications, I include this line in my dealloc.
[[NSNotificationCenter defaultCenter] removeObserver:self];
This is at the object level...so it will unregister for many notifications. It won't unregister for one notification in many objects.
Hope I understood your question correctly.
In case of Swift, you doing it like this:
NSNotificationCenter.defaultCenter().removeObserver(self)
And in Swift 3:
NotificationCenter.default.removeObserver(self)
Unfortunately, there is no way to remove all observers of a specific notification in one place. While there are certainly cases where this would be nice, it would be a dangerous thing to do as generally, the object doing the observing should be responsible for adding and removing itself as an observer of a particular notification. This ensures no unpredictable behavior b/c observers can come and go so they configure and clean up after themselves.
If an object that generates notifications goes away, it won't matter to the observer as the observer doesn't know about that object anyway. It just means that object won't be generating any more notifications.
[EDIT: RESPONSE TO YOUR COMMENT RE CLASS B STOPPING CLASS A FROM OBSERVING]
I just saw your comment. There are different ways to accomplish this, particularly if class B knows about class A. As you reference classes it sounds like you want to affect all instances of a class vs a particular instance. If you have some condition you can check when handling the notification, that's how I would approach this. In the notification handler something like:
if ([self shouldRespondToNotificationNamed:notification.name]) {
[self performNotificationAction];
}
If you don't have a condition you can check, then create one either in the class in question as an iVar or in a place where you can access it globally for all class instances. I generally use a singleton to store global app state that doesn't persist. If it persists, then use whatever method you're using for other state.

Resources