iOS: Releasing Object Thats In Use (ARC) - objective-c

I have an object that I have created that subscribes to some NSNotificationCenter notifications, but it is being released, since I don't have a pointer to the instantiation. The instantiation has a delegate that will call a method back to another class I have, so I felt it unnecessary to also have a pointer to it, since the pointer doesn't serve any purpose.
Basically, I have an instantiation of a class, DelegateListener (name is just for example purposes), which subscribes to some of the default NSNotificationCeneter's notifications. This instantiation isn't assigned to any pointer after the instantiation ends. The instantiation, however, has a property, delegate. I assign a value to that delegate during the instantiation. That delegate implements methods that I want the DelegateListener to call when the notifications that it subscribed to fire.
The problem with this is that the instantiation of DelegateListener that I create gets released, unless if I assign it to a retained pointer. Is there a way to avoid this automatic release of my DelegateListener instantiation within ARC?

You should store the DelegateListener instance in a static variable if you don't have multiple of them.
I felt it unnecessary to also have a pointer to it, since the pointer doesn't serve any purpose.
The pointer does (or at least should) serve a purpose: when you no longer need to listen to the notifications, you should unsubscribe the DelegateListener from receiving them. At the very least, this should happen when your application goes to the background (unless the point of it is to perform background processing), and when your application terminates.
[[NSNotificationCenter defaultCenter] removeObserver:delegateListener];

Related

Dealloc method isn't called when i release perticular object

I have created an object using alloc/init method, and after I release it -dealloc should be called immediately as per documentation. I set a breakpoint on -dealloc method but it isn't hit, and my -dealloc method is not called.
Please tell me what is the reason behind that, and what is use of dealloc method in objective c ?
The -dealloc method is not always called when you expect it to be called. The runtime might also have issued a -retain on your object for internal reasons.
It's also possible that you have (directly or indirectly) caused an extra -retain to be issued. If the retains/allocs and releases are not balanced, you'll never see -dealloc called. It helps to turn on the Static Analyzer, to make sure your calls balance.
Just follow the memory management rules, don't second guess the runtime, and let the memory management system do its job.
The answers to When does dealloc method call? may help you understand what you're seeing.
because it still has reference. that means its reference count not reached to zero. i don't know your code, where it is referencing. but it is not calling that means somehow still it has reference. it may be because of strong relationship or parent-child relationship
all Objective-C objects are allocated on the heap, so they must
therefore be deallocated somewhere if you are not to run out of
resources.
This gave way to the reference counting method, which is still used
today: each object keeps count of any references held to it. If you
receive an object and you want to keep it, you retain that object,
incrementing its reference count. When you are done with it, you
release it, which decrements its reference count. Once that count
reaches zero, it is inferred that no one is referencing the object and
it is automatically deallocated using the -dealloc method.
Additionally, an object could be told to “release at some point in the
(hopefully) near future” using autorelease pools. The idea is that
somewhere on the stack (typically at the start of a thread or while
responding to input events) an autorelease pool is created and pushed
onto a stack. Any object can then be sent an -autorelease message, and
it is assigned to that pool.
When the pool object is deallocated, it simply sends a -release
message to all its assigned objects. That way, any objects that are no
longer used (i.e. they haven’t been explicitly retained) are then
deallocated.
The dealloc is called (at more cases) whenever your object is released. You can't directly call this method.
#interface myViewController:UIViewController
{
NSString *myStr;
}
#end
Here the dealloc method in the #implementation of myViewController will be called (at most cases) when the myViewController object is released, not when myStr is released.
Although you don't have to use if you ARC.

In ARC do we need to send removeObserver: explicitly?

Do we have to send removeObserver: explicitly for objects that have been added as observers to an NSNotificationCenter before?
I am bit confused and unable to find the exact answer for this.
Please provide me in detail, about this including why we need to removeObserver explicitly, and why don't compiler put it implicitly in class/application?
Yes, you need to call removeObserver:, if you don't the observed class could call all deallocated instance of the observer.
From 10.11 observers are not required to un-register in their deallocation method.
NSNotificationCenter and NSDistributedNotificationCenter no longer
send notifications to registered observers that may be deallocated. If
the observer is able to be stored as a zeroing-weak reference the
underlying storage stores the observer as a zeroing weak reference.
Alternatively, if the object cannot be stored weakly (because it has a
custom retain/release mechanism that would prevent the runtime from
being able to store the object weakly) the object is stored as a
non-weak zeroing reference. This means that observers are not required
to un-register in their deallocation method.[1]
Removing the observer is always a smart idea.
If you don't remove the observer, messages will still be sent, even if the object was deallocated. It might even be attached to another object, which would definitely lead to serious trouble.
You always need to remove observers for KVO as well as for Notifications.

performSelector: afterDelay: without retaining the target?

I've got a class which uses NSURLConnection to open a long-running connection to a server. When the connection's closed, either in connectionDidFinishLoading: or connection:didFailWithError:, I want to wait 15 seconds then retry the connection.
At the moment I'm using [self performSelector:#selector(restartConection) withObject:nil afterDelay:15.0];, but this leads to the undesired situation that when the object is released by its creator, the performSelector and NSURLConnections perpetually retain 'self', and it never gets deallocated.
How can I do this without perpetually retaining the object? Any help'd be much appreciated.
Thanks, -Alec
I think your only option is to send
[NSTimer cancelPreviousPerformRequestsWithTarget: object];
at some point, probably, before releasing the object. If the timer hasn't been scheduled, this is a no-op, but is not free performance-wise.
You cannot avoid retaining the object. It is retained in order to save you from ugly crashes when in the next main loop cycle the runtime is going to call your selector on the released object.
If you really insist on having your object released immediately without waiting for your delayed selector, I would suggest you to create a separate proxy class. Say your class is called A, create proxy class B which will have a weak reference to your class A (i.e. __weak A* a) and restartConnection selector which will check if the weak reference is valid. If so it would invoke restartConnection on your A object. Then, do, of course, a delayed selector on B's restartConnection
But first of all, I would really suggest that you reevaluate whether you really cannot live with the retain.

How to properly deal with a deallocated delegate of a queued nsoperation

In my current project, several view controllers (like vc) spawn NSOperation objects (like operation) that are executed on a static NSOperationQueue. While the operation is waiting or running, it will report back to the view controller via delegation (operation.delegate = vc, assigned not retained).
These operations can take a while though, and in the mean time the app can dealloc the view controller (by popping them of a navigation controller's stack).
So far everything is intentional. The class containing the static NSOperationQueue has a way to get back at the operations, therefore the view controllers do not retain them. They're just alloc/init/autoreleased and put on the queue.
Now this also causes the problem. After the view controller deallocates, any calls to the NSOperation's spirited delegate will cause a bad access violation. From what I understand, it is not possible to check whether an object at a pointer has been deallocated, as stated in this question.
One fix I can think of is retaining the operation and setting the operation.delegate to nil on dealloc. But that'd be my least popular fix, for it would introduce a lot of extra ivars/properties to keep track of.
My question therefore is, are there other ways to work around this problem and if so, could you sketch one here?
Cheers,
EP.
SOLUTION: The approach that worked out best for me was a slight variation to Guiliano's answer:
Implementing every delegate protocol in the queue manager is not feasible (20+ different protocols with 50+ methods), so I kept the direct delegate assignments. What I did change was the class making the assign call. This used to be the class (and delegate) that created the request, but now it is offloaded to the queue manager.
The queue manager, next to assigning the delegate to the operation, also holds a secondary mutable dictionary to keep track of the delegate/operation pairs.
Every delegate instance calls a [QueueManager invalidateDelegate:self] method on deallocation, which then looks up the request that belonged to the delegate and nils it. The dictionary operation/delegate pair is then also deleted to allow proper deallocation of the operation.
Lastly with KVO observing the isFinished property of each operation, the mutable dict is kept clean, to make sure that all operation retain counts actually deallocate after they're finished.
Thanks Guiliano for providing the hint to using KVO for cracking this!
I would suggest to review your architecture and move the delegate to the class (assume QueueManager) that manages the queue instead of having a delegate in each operation:
Create a QueueManagerDelegate that
implements the method(s) you need to
notify the viewControllers
In QueueManager add a KVO observer for the isFinished property of each NSOperation (do this before adding the operation to the queue ;))
In the callback of the KVO call the delegate method(s) you need only if delegate is != nil
Add an invalidate method to QueueManager and call this method in the dealloc method of your UIViewController(s)
-(void)invalidate
{
self->delegate = nil;
}
in case you need a refresh on KVO: Kvo programming guide
The best advice here is to review the architecture of the app to avoid such situations. However, if there current code can't be changed some-why, you can use NSNotificationCenter. Every time your view controller is deallocated you can post a notification, this notifications must be caught by the NSOperationQueue holder, simple foreach cycle in the notification handler to nil the delegate for a deallocated view controller. Should do the trick.
You should also be checking to ensure that any delegates, if non-nil, are also able to respond to a message from the operation completion. You do this using the respondsToSelector function that all NSObject subclasses posess.
In my projects, I've abstracted this checking into a category on NSObject that lets me safely call delegates with an arbitrary number of object arguments:
- (void) dispatchSelector:(SEL)selector
target:(id)target
objects:(NSArray*)objects
onMainThread:(BOOL)onMainThread {
if(target && [target respondsToSelector:selector]) {
// Do your delegate calls here as you please
}
}
You can see the full example here: https://github.com/chaione/ChaiOneUtils/blob/master/Categories/NSObject-Dispatch.m

How do I handle memory management in this situation?

I have two classes, a class that handles db connectivity and an entity class. The db class has an instance method called GetEntityByID:(int)entity_id. This method does a simple select statement, and creates an Entity class instance using an init method.
This works fine, however whoever calls GetEntityByID must remember to release it. Since GetEntityByID is not an "init" method, this doesn't seem right. How do I best handle memory management in this situation?
You can call autorelease in your GetEntityID method on the class to autorelease the instance if it is not otherwise retained.
Since the instantiation of the class is done within your DB connectivity class's method, the object that is returned the instance does not "own" it - your DB connectivity class. As of this, according to convention, you need to memory manage the instance:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
If the object sending the GetEntityID method wants to keep the object around, for example if it is to be used as an instance variable, then the returned object can be retained, preventing it from being deallocated at the end of the current event. If it is only being used locally, and doesn't need to be kept around after the current event, then the class doesn't have to do anything; it will be released by the autorelease pool at the end of the current event.
This article explains more about autorelease pools.
To autorelease the object returned in GetEntityID do something like this in GetEntityID:
... // cool stuff in GetEntityID
return [[entity_id retain] autorelease];
}
Have a look at this really nice article explaining Objective-C memory mangement in more detail.