I know that in iOS 5 there is automatic reference counting which takes away the need for all of this but it is very simple anyway.
Is it good practice to set an object to nil before you release it or is it vice versa where you release it then set it to nil?
Anyway, I just want to get rid of any possibilities of crashes in my app and I just want this way to prevent it.
Thanks!
Calling release on nil accomplishes nothing.
When you use automatic reference counting, you cannot call release. It is a compiler error to do so.
In manual reference counting, you should release and then set to nil. Setting a variable to nil and then calling release leaks the object (it does not release it). It won't crash, but it will eat memory (eventually possibly so much memory that the OS will shut you down).
ARC is your absolute best tool for helping reduce crashes. There is no mechanism that can remove all possibilities of crashes. But two very simple rules will help:
Use ARC if at all possible.
Turn on "Treat Warnings as Errors." Never allow warnings in Objective-C.
There are many other smaller rules, but those are the two that every iOS developer should start with.
No, you don't set it to nil before you release the object, if you set it to nil, basically you lose pointer to your object, and now your variable is pointing to nil. Sending release to nil does nothing. If you want to protect yourself from garbage value / pointer, you can set it to nil, after you release the object. But, I don't see why you need to set it to nil other than if it's an instance variable.
Related
How can I check if object isn't deallocated on Objective-C?
The following standard condition checks only if object is initialized:
NSObject *objectVariable = nil;
...
if (objectVariable) {...}
You can't check after-the-fact whether an object is already deallocated or not, because it is invalid to do anything with an object that is deallocated (once an object is deallocated, any pointer that used to point to it is now an invalid pointer, and dereferencing it is undefined behavior). And since you don't know whether it is deallocated or not, and it may be deallocated, you cannot meaningfully examine it in any way. And a deallocated object may well "look like" a valid object if you try to examine it (it is undefined behavior, so any behavior is possible).
If this is an object of your own class, the obvious thing would be to print something or perform some other indicator action in the class's -dealloc method. That will tell you when it is deallocated.
Even if this is an object that is not of your own class, you may be able to either 1) add -dealloc as a category method, if the class doesn't override -dealloc, or 2) swizzle the -dealloc method, if the class does override it. Then you can print something in your version.
You can also profile it in Instruments; the Allocations instrument can tell you how many objects of a given class have been allocated, and how many are alive. If you suspect that you are losing track of objects or there is a retain cycle, the Leaks instrument may be able to tell you that.
I'm in agreement with the comments, If you're doing memory management right, there should be no need for such a check. Nor am I aware of such a check, if the address gets populated with a new object, the check would pass but could still crash your app.
My suggestions are to:
Read up on manual memory management rules, pay special attention to how blocks affect memory management, alloc/init methods, when to use assign, etc. Memory management rules should become second nature to you. Start with this Apple guide.
Run static analysis on your app and fix any memory errors. Fix all the errors really, these are bugs in your app. (CMD+Shift+B or Product->Analyze in the menu)
Reproduce the crash in Instruments using zombies. Read the retain/release report to find out where the object may have been over-released. (CMD+I or Product->Profile. Select Zombies in the window that appears)
Consider converting to ARC. Converting to ARC doesn't get you completely off the hook for understanding ObjC memory management, but it will take a lot of the burden off of you.
Someone just told me that, but I can hardly believe it. My app on the AppStore would have crashed all the time without this.
So is this true?
Nope; ivars are always initialized to zero/0/nil/NULL/Nil upon allocation.
In fact, when an Objective-C object is allocated, the memory associated with the allocation is effectively bzero()d.
I am trying to convert an old code to an ARC code.
However, i am getting a build error at the following line
[[token retain] autorelease];
I get 3 errors in the following order:
-'autorelease' is unavailable: not available in automatic reference counting mode
-[rewriter] it is not safe to remove an unused 'autorelease' message; its receiver may be destroyed immediately
-ARC forbids explicit message send of 'autorelease'
If i remove this particular line, then the code compiles correctly
If that is all that is on the line, you can probably just remove it. That code claims a reference to the object but also says you don't want to worry about releasing later, but with ARC you don't have to worry about it.
I am guessing that Xcode did not get rid of it automatically because of lack of context. If it had been in a more common location, such as in a return statement, it would be obvious what the intent was. When it is all by itself, it could be, but probably is not, something more complicated.
ARC manages your memory for you, so you don't need to call "autorelease", "release", "retain" etc. With ARC the compiler retain and release objects as necessary for you so you don't have to explicitly make these calls. If you want to manually manage your memory disable ARC, or you can use the compiler flag "-fno-objc-arc" to disable ARC on a specific class.
ARC means you don't have to use release, retain or those other pesky memory management things. ARC add them all for you automatically when you compile the app. Read more here
If you have old code where it would not be the best solution to remove all the memory management calls, then check this answer to disable ARC for particular files
How would you write a unit test—using OCUnit, for instance—to ensure that objects are being released/retained properly in Cocoa/Objective-C?
A naïve way to do this would be to check the value of retainCount, but of course you should never use retainCount. Can you simply check whether an object's reference is assigned a value of nil to indicate that it has been released? Also, what guarantees do you have about the timing at which objects are actually deallocated?
I'm hoping for a concise solution of only a few lines of code, as I will probably use this extensively. There may actually be two answers: one that uses the autorelease pool, and another that does not.
To clarify, I'm not looking for a way to comprehensively test every object that I create. It's impossible to unit test any behavior comprehensively, let alone memory management. At the very least, though, it would be nice to check the behavior of released objects for regression testing (and ensure that the same memory-related bug doesn't happen twice).
About the Answers
I accepted BJ Homer's answer because I found it to be the easiest, most concise way of accomplishing what I had in mind, given the caveat that the weak pointers provided with Automatic Reference Counting aren't available in production versions of XCode (prior to 4.2?) as of July 23rd, 2011. I was also impressed to learn that
ARC can be enabled on a per-file basis; it does not require that your
entire project use it. You could compile your unit tests with ARC and
leave your main project on manual retain-release, and this test would
still work.
That being said, for a far more detailed exploration of the potential issues involved with unit testing memory management in Objective-C, I highly recommend Peter Hosey's in-depth response.
Can you simply check whether an object's reference is assigned a value of nil to indicate that it has been released?
No, because sending a release message to an object and assigning nil to a variable are two different and unrelated things.
The closest you can get is that assigning anything to a strong/retaining or copying property, which translates to an accessor message, causes the previous value of the property to be released (which is done by the setter). Even so, watching the value of the property—using KVO, say—does not mean you will know when the object is released; most especially, when the owning object is deallocated, you will not get a notification when it sends release directly to the owned object. You will also get a warning message in your console (because the owning object died while you were observing it), and you do not want noisy warning messages from a unit test. Plus, you would have to specifically observe every property of every object to pull this off—miss one, and you may be missing a bug.
A release message to an object has no effect on any variables that point to that object. Neither does deallocation.
This changes slightly under ARC: Weak-referencing variables will be automatically assigned nil when the referenced object goes away. That doesn't help you much, though, because strongly-referencing variables, by definition, will not: If there's a strong reference to the object, the object won't (well, shouldn't) go away, because the strong reference will (should) keep it alive. An object dying before it should is one of the problems you're looking for, not something you'll want to use as a tool.
You could theoretically create a weak reference to every object you create, but you would have to refer to every object specifically, creating a variable for it manually in your code. As you can imagine, a tremendous pain and certain to miss objects.
Also, what guarantees do you have about the timing at which objects are actually released?
An object is released by sending it a release message, so the object is released when it receives that message.
Perhaps you meant “deallocated”. Releasing merely brings it closer to that point; an object can be released many times and still have a long life ahead of it if each release merely balanced out a previous retain.
An object is deallocated when it is released for the last time. This happens immediately. The infamous retainCount doesn't even go down to 0, as many a clever person who tried to write while ([obj retainCount] > 0) [obj release]; has found out.
There may actually be two answers: one that uses the autorelease pool, and another that does not.
A solution that uses the autorelease pool only works for objects that are autoreleased; by definition, objects not autoreleased do not go into the pool. It is entirely valid, and occasionally desirable, to never autorelease certain objects (particularly those you create many thousands of). Moreover, you can't look into the pool to see what's in it and what's not, or attempt to poke each object to see if it's dead.
How would you write a unit test—using OCUnit, for instance—to ensure that objects are being released/retained properly in Cocoa/Objective-C?
The best you could do is to set NSZombieEnabled to YES in setUp and restore its previous value in tearDown. This will catch over-releases/under-retains, but not leaks of any kind.
Even if you could write a unit test that thoroughly tests memory management, it would still be imperfect because it can only test the testable code—model objects and maybe certain controllers. You could still have leaks and crashes in your application caused by view code, nib-borne references and certain options (“Release When Closed” comes to mind), and so on.
There's no out-of-application test you can write that will ensure that your application is memory-bug-free.
That said, a test like you're imagining, if it were self-contained and automatic, would be pretty cool, even if it couldn't test everything. So I hope that I'm wrong and there is a way.
If you can use the newly-introduced Automatic Reference Counting (not yet available in production versions of Xcode, but documented here), then you could use weak pointers to test whether anything was over-retained.
- (void)testMemory {
__weak id testingPointer = nil;
id someObject = // some object with a 'foo' property
#autoreleasepool {
// Point the weak pointer to the thing we expect to be dealloc'd
// when we're done.
id theFoo = [someObject theFoo];
testingPointer = theFoo;
[someObject setTheFoo:somethingElse];
// At this point, we still have a reference to 'theFoo',
// so 'testingPointer' is still valid. We need to nil it out.
STAssertNotNil(testingPointer, #"This will never happen, since we're still holding it.")
theFoo = nil;
}
// Now the last strong reference to 'theFoo' should be gone, so 'testingPointer' will revert to nil
STAssertNil(testingPointer, #"Something didn't release %# when it should have", testingPointer);
}
Note that this works under ARC because of this change to the language semantics:
A retainable object pointer is either a null pointer or a pointer to a valid object.
Thus, the act of setting a pointer to nil is guaranteed to release the object it points to, and there's no way (under ARC) to release an object without removing a pointer to it.
One thing to note is that ARC can be enabled on a per-file basis; it does not require that your entire project use it. You could compile your unit tests with ARC and leave your main project on manual retain-release, and this test would still work.
The above does not detect over-releasing, but that's fairly easy to catch with NSZombieEnabled anyway.
If ARC is simply not an option, you may be able to do something similar with Mike Ash's MAZeroingWeakRef. I haven't used it much, but it seems to provide similar functionality to __weak pointers in a backwards-compatible way.
this is possibly not what you're looking for, but as a thought experiment I wondered if this might do something close to what you want: what if you created a mechanism to track the retain/release behavior for particular objects you wanted to test. Work it something like this:
create an override of NSObject dealloc
create a CFMutableSetRef and set up a custom retain/release functions to do nothing
make a unit test routine like registerForRRTracking: (id) object
make a unit test routine like clearRRTrackingReportingLeaks: (BOOL) report that will report any object in the set at that point in time.
call [tracker clearRRTrackignReportingLeaks: NO]; at the start of your unit test
call the register method in your unit test for every object you want to track and it'll be removed automatically on dealloc.
At the end of your test call the [tracker clearRRTrackingReportingLeaks: YES]; and it'll list all the objects that were not disposed of properly.
you could override NSObject alloc as well and just track everything but I imagine your set would get overly large (!!!).
Even better would be to put the CFMutableSetRef in a separate process and thus not have it impact your program runtime memory footprint overly much. Adds the complexity and runtime hit of inter-process communication though. Could use a private heap ( or zone - do those still exist?) to isolate it to a lesser degree.
In the section titled 'Memory Warnings' here http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmNibObjects.html, I don't follow why the IBOutlet is set to nil in the dealloc. If
self.anOutlet = nil
causes a crash as mentioned in the topic, why are they setting the ivar to nil?
In general, why would you set an ivar to nil in the dealloc when you are already calling release?
After a release, the pointer is essentially invalid and accessing it again may cause a crash. By setting a variable to nil after release you prevent that crash from happening. There's no harm in accessing a nil pointer.
The example you've linked to simply demonstrates why it's always a good idea to set a variable or ivar to nil after release, even when it looks like the variable/ivar won't be accessed again.
In the example, the anOutlet ivar is actually accessed by the superclass after your dealloc method, so if you don't set it to nil you will get a crash. Scenarios like that are very hard to spot just by looking at the code, so it's a good idea to nil every variable after release, even in dealloc.
Sending a message on an object that is released causes a crash, sending a message to a nil object is ignored.
Sometimes a crash is a good thing, and a quick solution would hide a deeper problem. Calling a released variable might be something you want to know about.
The book iOS Recipes refers to this issue:
Cleanup in -dealloc
In addition to releasing all relevant instance variables in the -dealloc, our examples set them to nil. This practice is one of the most hotly debated topics among Cocoa programmers, and both sides of the argu- ment hold weight. This book is not meant to participate in the debate at all: we set them to nil, but that doesn’t mean you have to. If you don’t like nil-in-dealloc, feel free to leave it out of your own code.
A quick google search found this thread:
http://www.cocoabuilder.com/archive/cocoa/204055-why-should-we-set-ivars-to-nil-in-dealloc.html
Sometimes when one property becomes invalid (set to nil) we want to make other properties invalid too. If a class invalidates a property by using self.property_name=nil, then this will send a release message, which will cause a crash in dealloc if we have already called release on that property. If the invalidation occurs in a superclass, then this error is hidden and quite nasty. So whenever a superclass might invalidate a property it may be a good idea to set it to nil rather than just deallocing.