If I am using a block when making an asynchronous operation and the block references objects and properties of the view controller, does the block retain them and thereby making the view controller not get deallocated if the user leaves the view controller before the async operation ends?
Yes. Blocks are Objective-C objects and will retain any referenced objects. You can ask them not to, of course.
See: http://thirdcog.eu/pwcblocks/#objcblocks
Related
The title almost covers it. I understand why use weakSelf inside blocks.
But imagine a situation where we have a view controller. The view controller calls a data API (a singleton shared instance) which has a completion block. So in this call VC provides a completion block to which the VC doesn't hold a reference.
There is also a private convenience method inside VC which does something to a UI component and calls self.
But this private convenience method is called inside the block.
So knowing that, should I use weakSelf in the convenience method too?
One would use weakSelf pattern wherever:
You would otherwise have a strong reference cycle;
You are using cancelable asynchronous tasks and wish to cancel them in dealloc; or
If the view controller is dismissed while the asynchronous call is still underway, you do not want it retained for the duration of the asynchronous call.
This latter point means that one may use weakSelf pattern in conjunction with completion blocks for asynchronous methods, regardless of whether there is a strong reference cycle or not. The question is simply whether you need the view controller retained for the duration of the asynchronous call even if the view controller has since been dismissed.
If I understand you correctly, you do not store the block into a property of self (or into an object referring self and so on). So there is no reason at all to use weakSelf, because a retain cycle cannot be built.
Using xcode 4.2 for iPhone app, without ARC ---
When I create an outlet using the interface builder xcode adds two lines of code to my viewController. One in viewDidUnload: -- [self setMyOutlet:nil] and second in dealloc -- [myOutlet release].
I understand the latter (the release). But why set the outlet to nil in viewDidUnload. Doesn't viewDidUnload get called before dealloc and won't setting the outlet to nil negate the release operation in dealloc? Setting to nil makes sense I would think for building a Mac application which is using garbage collection -- but it doesn't make sense for an iPhone app.
Why does the interface builder do this? Should I delete the lines which set the outlets to nil?
viewDidUnload may be called and may be not called. It depends on the current memory usage. dealloc is a place where you should clean all your properties (like arrays, custom objects). In viewDidUnload you clean views and perhaps objects created to support the view. viewDidUnload mean that your view is unloaded (but not whole view controller) and it may be created and loaded again (in viewDidLoad, of course) in the future.
Why to nil - Objective-C Difference between setting nil and
releasing
Understanding How Views Are Loaded and
Unloaded
viewDidUnload is not called everytime before a dealloc, see what the apple docs say..
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. If your
view controller stores separate references to the view or its
subviews, you should use this method to release those references. You
can also use this method to remove references to any objects that you
created to support the view but that are no longer needed now that the
view is gone. You should not use this method to release user data or
any other information that cannot be easily recreated.
so the idea behind it is too release any unwanted objects which can be created easily.
Now coming to the part where it sets the properties to nil.. it does so because this way you release all the memory and set the objects to nil (thus bringing your down your memory usage) and after this if a dealloc is called your app will not crash as in objective-c you can send release messages to nil objects..
I would advise you to read the apple ViewController Programming Guide , it will clear a lot of your questions.... hoping this clears some of the air.. :D
When should I release all the memory I allocated in my program?
Because I only have a viewDidLoad method where I do my business. Should I leave dealloc empty and cleanup only in viewDidUnload?
'dealloc' is used when the object is ready to be freed (i.e., when retain count of the object becomes 0). And viewDidUnload is called when the view is unloaded, but it may not be freed immediately as the reference of the UIViewController is still stored by some other objects.
my personal preference is, for ojbects created by 'init', they are freed by 'dealloc', for objects created by 'viewDidLoad', they are freed by 'viewDidUnload'.
As the documentation of -viewDidUnload says:
It is called during low-memory
conditions when the view controller
needs to release its view and any
objects associated with that view to
free up memory. Because view
controllers often store references to
views and other view-related objects,
you should use this method to
relinquish ownership in those objects
so that the memory for them can be
reclaimed. You should do this only for
objects that you can easily recreate
later, either in your viewDidLoad
method or from other parts of your
application. You should not use this
method to release user data or any
other information that cannot be
easily recreated.
Typically, a view controller stores
references to objects using an outlet,
which is a variable or property that
includes the IBOutlet keyword and is
configured using Interface Builder. A
view controller may also store
pointers to objects that it creates
programmatically, such as in the
viewDidLoad method. The preferred way
to relinquish ownership of any object
(including those in outlets) is to use
the corresponding accessor method to
set the value of the object to nil.
However, if you do not have an
accessor method for a given object,
you may have to release the object
explicitly.
There is no mention -viewDidUnload will call in -dealloc, you shouldn't rely on it.
if i create an instance of my object in the interface builder, it gets destroyed by the garbage collector immediately after loading. What is a clean way to counter this?
I figured out that i can do a [self retain] in the constructor or create an outlet in the window controller. I just think there must be a better official way to do this?
Thanks, Chaosbit
Orphaned objects are generally not a good idea except in special cases, so it's normal that every object have has some other parent object that keeps a reference to it (and retains it).
The best way to achieve this reate an outlet on your window controller (or somewhere else appropriate) and ensure it has the retain attribute set on the property.
(on a sidenote, your object isn't being Garbage Collected, as there is no such thing on Cocoa Touch. It's being autoreleased, which is a different concept)
I would like to use KVO in the following context:
1) In touchesBegan:withEvent: I alloc/init an instance of an object that I then observe via KVO
My intent is to observe varous behaviors of the object throughout its life time.
2) In touchesEnded:withEvent: I assign this instance to an NSMutableArray and release the instance reference since NSMutableArray now retains it. I also must remove the oberver of the instance via removeObserver:forKeyPath:
This is problematic because I now have lost all observation unless I add the observe back again to the array element which smells bad.
Is there a way to have the observer remain attached to the object regardless of who owns it?
Thanks,
Doug
In Objective-C, you don't "own" an object, you merely have a claim on it. You don't need to release the instance just because the NSMutableArray retains it -- you can both have a claim on it. When you've finished with the object, remove yourself as an observer and release the object. When you've finished with the NSMutableArray, release that. This way, everything takes care of itself.