ARC in iOS 6 versus in iOS 5 - iphone

I am new to ARC. My issue is that if we create a strong type property on a view controller, we need to make it nil once the navigation controller's popViewController happens.
Normally, we would do that in viewDidUnload. But in iOS 6 it's deprecated.
So where do we make that object nil? Apple says to do it in didReceiveMemoryWarning but that method does not get called every time when we pop the view controller.

Don't worry about it. Your properties will all get set to nil automatically by the Objective-C runtime in dealloc. This is true of all properties, not just outlets on a view controller.

You define a property strong if you want to keep ownership on the referenced object.
From what I can understand you probably need a weak property (when your object is released by someone else you don't need it and it can be deallocated) or maybe a workaround could be set it to nil in the viewDidDisappear method, but as Jim Puls said, without seeing you code mine are just educated guesses...

If you're popping/pushing between the same two view controllers, then the pointer in the UINavigationController shouldn't change as long as they don't get dealloc'ed. If they do get dealloc'ed then everything in them should get dealloc'ed too. You may end up creating new copies of these view controllers but that shouldn't be a problem because you're only creating new copies if the old ones were already dealloc'ed. The only way you can be retaining objects is if your view controllers (or objects within them) are referencing each other, causing them to be retained.
The difference between strong and weak is not that you need to manually set strong to nil. Rather, a strong relationship will cause an object to be retained, while a weak will not. That's why delegates are usually set to weak since you don't want a delegate retaining its parent (not parent exactly, but the object that it's a delegate of).

Related

Why would adding a delegate to a UINavigationController crash my app?

I'm working on an iPhone application. I'm using Storyboard.
I wanted to have one object attached to the NavController to handle the visibility of the button bar at the bottom of windows that display table views.
I created my own UINavigationDelegate; MyNavigationControllerDelegate.
I have created an NSObject in UIBuilder and changed its class MyNavigationControllerDelegate. And then attached it as the delegate of the UINavigationController.
For some reason MyNavigationControllerDelegate is getting deallocated. I would have thought that being the delegate would be enough to keep a reference to it and prevent deallocation, but that seems not to be the case.
Any suggestions as to how to prevent it from being deallocated? And do I have to reset it as the delegate each time a view is loaded?
The delegate property of UINavigationController is declared as assign rather than retain or strong (see here). Delegates are typically declared either weak or assign, which means assigning the property will not cause the UINavigationController to increase the reference count on your delegate, and you need another object to hold a strong reference to it (perhaps your RootViewController).

ARC and Interface Builder

I have an interesting question about interface builder and ARC. I am building a view controller that will be initialized with a xib. I use the tap-and-drag capability of interface builder to create necessary property outlets for my xib. This initalizes the property as (weak, nonatomic). Sounds fine to me.
What's throwing me off is that lines such as [self setCategoryButton:nil]; are automatically added to viewDidUnload. I understand and used this before ARC. However, since these are weak references, wouldn't they automatically be cleared when the view unloads?
I suppose I could see the value in nil-ing these properties if those views are retained by other objects, but that seems an unusual case to me... Just wanted to get further feedback on the point.
Thanks,
Kurt
I filed a bug on this a while back, and the response that I got was that this is intentional behavior. Since Xcode cannot verify that there are no other strong references to the view, it cannot actually guarantee that the weak pointer would be automatically cleared in -viewDidUnload. Thus, they clear it for you.
Personally, I think this is a lame reason, but that's the reason that was given.
It will only be set to nil in iOS5 or later (iOS 4 does not automatically nil weak pointers), so it is there for safety in the auto generated code. I've been wondering about this myself and that's the only reason I can come up with.
From Documentation, the viewDidUnload
"This method ...is your chance to perform any final cleanup. ... "
"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"
From Documentation, about weak (Setter Semantics)
Specifies that there is a weak (non-owning) relationship to the destination object.
If the destination object is deallocated,the property value is automatically set to nil.
So it's obvious. It's consistant on the rules.Is not about the object that your property points,but just nullify your property based on the above rule of weak.
The viewDidUnload suppose that's your weak property can't be point to any object,
because that object is deallocated (based on the place of viewDidUnload in the life cycle of a View Controller). And simply cleans it with the nil.
It's safe for you, explicit to the weak rule and memory efficient.
The compiler can't be sure that you took the care about the pointed object.
He just need to ensure the clean up.
Since the property is weak, the reference in your object won't affect the retain count of the object. So yes, there's no point in setting the object as nil. At least that's how I understand it.

UIViewController not releasing subviews when dealloc (using ARC)

I have what seems like a weird (non?) issue with UIViewController. It appears that the controller is not releasing its subviews when it is dealloc'd. I placed NSLog messages in all of the subview's dealloc method as well as the view controller. The view controller dealloc gets called but the subview's do not. However, if I then push another instance of that view controller on to the navigation stack, it appears that all of the subviews of the previous instance are then released (I get a bunch of NSLog messages in the console letting me know). I've check and I have no separate reference to the custom view controller in the presenting view controller (the one that's doing the pushing).
One small (maybe) detail: The custom view controller does receive a block it stores and then executes before popping. However, I did send nil to it and I get the same behavior. Plus, the presenting view controller does dealloc when popped of the stack, so no retain cycle.
Also, I did try explicitly releasing each view in the dealloc method of the custom view controller. Same behavior.
Is it possible the navigation controller would be holding on to it? It doesn't seem to do this to any of my other view controllers.
My problem is that this does represent a memory leak (of all those subviews); though the leak doesn't stack, it's still a leak.
Ok, this is embarrassing. I did find the problem in another class (called ViewDef) I was inadvertently using as a collection class. It was a quick and dirty way of keeping track of my subviews when I was first figuring out some animations (months ago). ViewDef stored frame/font/color/etc info retrieved from a database, so it was convenient to also store the views when figuring out animations (between orientations). These ViewDefs were being store by my model and passed around, so of course the views were also being retained (and replaced later by another view controller). Anyway, I forgot to insert a warning in my code to fix this later.
Moral of the story: If you plan on doing something stupid, at least document your stupidity so you don't have to broadcast it over the internet later.
you could try setting the subviews to nil in the viewDidUnload method maybe that will help
One thing to try is to make sure all your subviews delegates are set to nil.

How to properly compose a "viewDidLoad" method

I'm not entirely new to iPhone dev, but I ran across a situation where I was unsure about the best design choice for my code.
I have a view controller which asynchronously fetches an image from the internet and loads it into an image view. When the app receives a memory warning however, the imageView is released by didReceiveMemoryWarning. If the app receives a memory warning while loading an image, the imageView is nil by the time my code tries to load the image into the imageView.
What is the best practice for viewDidLoad? Should I just instantiate any variables that I may need later on? Or should I just check for nil values elsewhere in my code?
Also, in viewDidUnload, should I just set IBOutlet variables to nil? Why is this?
Thanks! -Matt
Why not just create the image view on demand when the image is loaded? No need to create it any earlier. Or, if you do, then just have code to recreate it if it has been released.
In viewdidunload you should release resources that you created in viewdidload (or load view). Including any IBoutlets that interface builder hooked up for you. It's good practice to set these variables to nil to ensure they won't be inadvertently accessed after release, or double released.
IBOutlets can be both instance variables and properties. In both case, we should release the references when the view, which is top most superview, is unloaded. Setting the IBOutlet retained properties to nil releases the reference automatically, but for instance variables we need to release them. We still need to set instance variables to nil because viewDidUnload is not dealloc, so we must comply with the managed memory rule or we might have invalid references sitting around inside the instance.
I don't think there are rules about what you should do in viewDidLoad, but if you did release and set some variables to nil in viewDidUnload, you need not have to check for nil again in the viewDidLoad unless you don't trust the framework.

memory management with outlets and properties in view controllers

Hey guys, sorry for beating the memory management (dead)horse again. I know this question has been asked several times on SO, but I feel all the threads out there is still lacking two pieces of information. Let me put forth what I DO know to save everyone some time.
1) When you create an IBOutlet, your view controller automatically retains this outlet.
1a) When you don't create an outlet, the 'framework'(the nib?) releases your objects(like uilabels or uiviews) for you.
2) When you do self.myOutlet = nil, you effectively release an outlet(providing that you have synthesized your properties correctly). This is because the setter releases the outlet and assigns it to nil.
What I don't know:
1) The MAIN question: If you do self.myOutlet = nil in viewDidUnLoad, do you still need to do anything in dealloc? Can you make the assumption that viewDidUnload always called before dealloc?(and therefore your retained views are released?)
2) If you don't synthesize a property for that outlet, what happens? Shouldn't the framework release it automatically?(since you don't have a retain property) If you do have to release it, how do you do it and where(in viewDidUnload or dealloc)?
If anything is wrong, please point it out to me. Any clarifications at all would be very helpful.
(#1) The Apple docs say to do both
In addition, because of a detail of the implementation of dealloc in UIViewController, you should also set outlet variables to nil in dealloc:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmNibObjects.html
(#2) If you don't synthesize a property, you still need to make a property, and it better retain -- read the link. The UI object is created, autoreleased and the outlet property is set (which is supposed to retain). There is no release called for you because they already did the release they were supposed to do -- you retained, so you have to release (in both viewDidUnload and dealloc)