UIViewController and NSURLConnection - ios

I create and launch a NSURLConnection in UIViewController's viewDidLoad. And UIViewController is set as a delegate for the NSURLConnection.
What will happen if UIViewController destroys (deallocates) before NSURLConnection has finished its work? It will try to call a delegate, I guess, and the app will crash.
Previously (before using ARC), I used to remember NSURLConnection by a strong reference and cancel it in UIViewController's dealloc method.
Should I do something similar when using ARC. And if not, why?

Why wouldn't you do the same thing when using ARC? If this was important to do before ARC, it is important to do after ARC. Memory management is memory management. The danger of a message being sent to a delegate that no longer exists is exactly the same. It's all the same, ARC or no ARC — except that under ARC, retain and release are being called for you.

NSURLConnection must be storing some internal reference of connection object that why it wont be crashing. Personally i have been keeping strong reference as we don't know how actually internally sdk save these references and this behavior may also change with sdk.
You can avoid crashing when viewcontroller dealloc before connection object by setting delegate method to nil and calling cancel method on the instance

Related

Invalidating an NSTimer in dealloc

Following this question, and more specifically, this comment:
because retain (aka strong reference) cycles in the common case where the timer's target is also its owner
I am wondering why dealloc isn't a good place to invalidate an NSTimer.
I remember profiling my app without auto-repeating NSTimer invalidation and then with invalidation in dealloc, and the memory correctly freed.
Is dealloc working differently in the latest iOS?
Isn't in fact your overridden dealloc called prior to any NSObject deallocation? What is dealloc even used for, then? If not manually deallocating the respective object's properties?
ARC will only release ( and call dealloc ) objects, when there are no strong references pointing to this object ( no one is retaining ).
NSTimer creates strong reference and it will retain target.
This means, dealloc will not be called, because NSTimer still has strong reference to the object. If there is no dealloc, this means NSTimer will never be invalidated ... leads to memory leak or even crashes.
There is a way to invalidate timer in dealloc or when target becomes nil. Have a look at the answer here.

Is there a way to be alerted when a view controller or any object for that matter is released because of a retain count of 0 in ARC?

There used to be dealloc but since ARC that's gone.
I need some way to be alerted of exactly when an object is freed (and I'd rather not use Instruments since it's really slow and just not working for me right now.)
That's not correct, the method dealloc of NSObject still exists.
See Docs here.

How should I tidy UIViewControllers when they need to be destroyed

I'm starting to write the second version of our iPhone app and I'm trying to tidy up previous mistakes (as it's my first attempt at Objective-C). My question is related to "things I need to do when a UIViewController is destroyed", there seem to be a few contradictory answers out there and I want to make sure I understand correctly.
Couple of constraints:
This code is for use with iOS 5 and iOS 6 devices
I don't wish to register and deregister NSNotifications on viewWillAppear and viewWillDisappear because the UIViewControllers need to receive notifications even if they can't be seen by the user.
I'm using a StoryBoard rather than separate nib files.
So considering the above constraints, are the following statements true?
IBOutlets connecting the storyboard to the UIViewControllers should be weak, the strong reference will be created behind the scenes.
Because the IBOutlets are weak I shouldn't need to nil them out in low memory situations
I shouldn't use viewDidUnload because it's being deprecated instead I should use didReceiveMemoryWarning. In this situation I only need to nil out strong properties (that can re-calculated)
It's acceptable to register for NSNotifications on viewDidLoad.
Because I wish to continue receiving notifications when the view is hidden, the best place to unregister them is in dealloc, there's no benefit in also unregistering them in didReceiveMemoryWarning.
Thanks for your help,
Dan
IBOutlets connecting the storyboard to the UIViewControllers should be weak, the strong reference will be created behind the scenes.
No. NSKeyedUnarchiver (NSCoder) does not change the storage qualifiers associated with user-created outlets. You keep them weak because you don't ever explicitly alloc and init IBOutlets, therefore you do not "own" them in the cocoa sense of the word.
Because the IBOutlets are weak I shouldn't need to nil them out in low memory situations
Not true at all. Zeroing weak references zero out in dealloc, not in low memory situations. Apple expects you to do that by explicitly releasing strong outlets to handle memory warnings.
I shouldn't use viewDidUnload because it's being deprecated instead I should use didReceiveMemoryWarning. In this situation I only need to nil out strong properties (that can re-calculated)
Yes, but as for the replacement for -viewDidUnload, dealloc serves that purpose.
It's acceptable to register for NSNotifications on viewDidLoad.
Because I wish to continue receiving notifications when the view is hidden, the best place to unregister them is in dealloc, there's no benefit in also unregistering them in didReceiveMemoryWarning.
Absolutely.
I believe what you say is correct. Regarding IBOutlets and strong/weak references, see this thread.
As for notifications: unregistering them in didReceiveMemoryWarning seems pointless as they are not by themselves freeing any memory upon de-registration. Therefore you're right in deregistering them upon deallocation.

Strange behaviour while deallocation of an object

I have a view, which is subclass of UIWebView. It has a property called Contact which is a managed object. The view uses templating engine to create a html with the object and then load into UIWebView. I thought it would be a better idea to monitor the object in the view itself, such that whenever something changes in the object, the view refreshes automatically. So, observed for certain attributes of the managed object in the view itself. And then to avoid the notification coalesce, I have made it such that the reload is done with
[self performSelector:#selector(refresh) afterDelay:0 ].
It refresh the webview automatically whenever it finds the change but also gives some strange crash. The crash says [MyWebView retain] message sent to deallocated object. I know I have properly removed observing values in dealloc method. But, it seems like dealloc gets triggered after a while. I have a strange issue related to releasing the view. The view stays for a while, although the view controller is already released and then releases after may 2/3 seconds. It is really strange. I think the crash is because of this.
Please do suggest me any idea. I will be glad to hear your suggestion. There are something wrong certainly, if anybody could point me I would really be grateful.
Using the delegate design pattern can cause EXC_BAD_ACESS KERN_INVALID_ADDRESS crashes if not used properly. If you have processing that is running in background threads that use the delegate design pattern, where in the object you set SELF as the delegate then you must remove SELF as the delegate in the dealloc method (even under ARC) by setting the delegate reference to nil, or there is a possibility that the object will try to call back into your deallocated object using the delegate design pattern. So if you have something like this in your object.
[_xmlParser setDelegate:self];
you should always have a dealloc method even under ARC to prevent the possibility of a crash in the case where your object gets destroyed while still doing work. It is very common to have your object destroyed while doing work. imagine a UIViewController that shows images from the internet. If you had a FetchImage class that used the delegate design pattern to lookup images that then calls a routine on the object when the lookup finishes, it is easily for the user to pop into and out of your UIViewController while your FetchImage object is still doing work on the background thread. You might not ever notice this when testing, but if you have hundreds of users, some of them will notice because the app will crash when your object tries to call a method on the SELF reference.
If your object uses the delegate design pattern, always have this to cleanup:
#pragma mark - dealloc - cleanup delegate references to prevent callbacks into deallocated objects (EXC_BAD_ACCESS / KERN_INVALID_ADDRESS)
- (void)dealloc
{
[_xmlParser setDelegate:nil];
// for non ARC based code you would also call: [super dealloc];
}
search every class in your project, if you have setDelegate:self or delegate = self then your users are most likely experiencing race condition crashes with your app if you don't have a dealloc cleanup method as described above. If you don't have the dealloc, add it even if you never see crashes when testing. -rrh

Receive memory warning and memory leak

I'm using ARC (automatic reference counting).
Is it ok if I set the IBOutlets to nil in the viewDidDisappear instead of viewDidUnload?
Such as these:
[self setTheImage:nil];
[self setBTNplay:nil];
[self setBTNstop:nil];
I'm writing a navigation based app which includes pageViewController, I tested my app in Instruments to see the memory leaks and I keep getting receive memory warning message.
I've even put a log code in the viewDidUnload method. But it doesn't seem to get called when I even pop to rootViewController!
One more thing: If each page has an audioPlayer, where should I set a #property (nonatomic, strong) AVAudioPlayer *audioPlayer; to nil?
Or how do I set it to weak instead of strong? Because it gives me a 'warning' then in this code line:
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:poemURL error:nil];
it says: Assigning retained object to weak variable
You don't need to nil out those values in viewDidUnload. Make sure you're using weak properties instead of strong or assign for IBOutlets. Received memory warning doesn't necessarily mean you're leaking. Received memory warning means that your app is consuming too much memory. Run Instruments and edit your question with how much memory your app uses.
The fact that you're using AVAudioPlayer makes me thing that maybe you're pulling down some massive audio files into memory.
Also by the way, initWithContentsOfURL:error: will get you rejected from the App Store because you're blocking the main thread. Try testing your app on an iPhone with only cellular enabled and go into a part of your office/house that has a bad internet connection. Also try with your phone switched to airplane mode. Your app will undoubtedly either freeze for a long time before the connection fails or it will simply crash.
Instead, you should be using grand central dispatch or downloading it via NSURLConnection's block or delegate methods.
First, do not set to nil your properties in viewDidDisappear cause your view is still loaded. You must always set them to nil in viewDidUnload. It's invoked in low memory situations and here you must clean-up all stuff that breaks system memory.
Apple's UIViewController reference for viewDidUnload
When a low-memory condition occurs and the current view controller’s
views are not needed, the system may opt to remove those views from
memory. This method is called after the view controller’s view has
been released and is your chance to perform any final cleanup.
Second , take a look at this tutorial where is explained very well ARC
Are you calling [[NSNotificationCenter defaultCenter] removeObserver:self]; from one of your view controller subclasses? If so, that would explain why you're not getting viewDidUnload called.
If that's the problem, you should remove yourself from specific notifications when needed rather than all notifications as above. (It's OK to call removeObserver:self from dealloc, though.)
Is it ok if I set the IBOutlets to nil in the viewDidDisappear instead
of viewDidUnload?
There are many things wrong from this statement.
First of all, you do not set IBOutlets to nil in viewDidDisappear. viewDidDisappear is called when the view "disappears" (e.g. when it's in a tab bar controller, and you switch to another tab; or it's on a navigation controller, and you push something on top of it); the view can then "appear" again without loading again. If you set IBOutlets to nil, they will not be set again when you appear. (They are only set when the view is loaded.)
Second, if you have a leak, and setting stuff to nil "fixes it", that means you are not releasing the instance variables. You must always release retained instance variables in dealloc.
I've even put a log code in the viewDidUnload method. But it doesn't
seem to get called when I even pop to rootViewController!
Yes, viewDidUnload is only called in low memory situations. It is not called normally in most situations. If you were depending for it to be called, you were using the wrong method.

Resources