I'm new to Objective C. I see in many iPhone/iPad applications that after releasing an object, it would then be set to nil.
[self.obj release]
self.obj = nil;
I assume this is done so as not to leave the pointer to reference a memory location that is now deallocated. Now assume the following situation:
//Thread #1 code
..some code
..some code
[self.obj release]
-------> Thread #2 runs //Thread #2 code
..some code
if (self.obj){
some code
}
self.obj = nil; <----- Thread #1 runs
I was wondering if this situation possible? And if it is, is there a way to make the release/nil atomic?
this is actually not entirely correct
[self.obj release]
self.obj = nil;
you should write simply
self.obj = nil;
which will call the setter that will release the previous instance.
Yes, it could blow up. Consider your code example.
[self.obj release];
self.obj = nil;
You use self.obj which means you are referencing accessor/mutators methods instead of accessing your object directly. Chances are you'd declare "obj" as a retained property. Your .h would be something like...
#property (retain) Something *obj;
and your .m
#synthesize obj;
If you later release your object by using the methods created by your #synthesize you are safe.
[self setObj:nil];
// or equally valid
self.obj = nil;
// Below is (almost) identical way to access, release and nil the variable directly.
// The major difference is you don't multi-threaded protection of your property
// declaration (explained below).
[obj release];
obj = nil;
If you look back at the property I specified above you'll notice I didn't put in the very commonly seen nonatomic. It wasn't by accident. Take a look at Apple's docs
Properties are atomic by default so that synthesized accessors provide robust access to properties in a multithreaded environment—that is, the value returned from the getter or set via the setter is always fully retrieved or set regardless of what other threads are executing concurrently.
You can surround both operations in an #synchronized block to ensure that both operations complete before leaving the block:
#synchronized(lockObject)
{
[self.obj release];
self.obj = nil;
}
Provided that any other threads that might access that variable also synchronize around the same lock object, you shouldn't run into any issues.
Related
I using Test Driven Development in Objective-C for iOS and Mac OS X development, and I want to be able to write tests that can verify that objects I create with class factory methods return autorelease objects.
How can someone write a test that verifies a provided object is autorelease?
In short, you can't. There is no way to know the autorelease state of an object.
In some cases, you can infer whether an object was placed in an autorelease pool. The idea is declaring a pointer to an object, instantiating it within an #autoreleasepool block, and then verifying that it had dealloc called after the end of the block.
Through whatever combination of swizzling or overriding dealloc you choose, you must first provide a way to verify that dealloc has been called. I wrote an NSObject category with the following interface and implementation, that provides a deallocationDelegate property that will receive a message of handleDeallocation: when the object is deallocated.
#interface NSObject (FunTimes)
#property (nonatomic, assign) id deallocationDelegate;
#end
#implementation NSObject (FunTimes)
+ (void)load
{
Class klass = [NSObject class];
SEL originalSelector = #selector(dealloc);
Method originalMethod = class_getInstanceMethod(klass, originalSelector);
SEL replacementSelector = #selector(funDealloc);
Method replacementMethod = class_getInstanceMethod(klass, replacementSelector);
if(class_addMethod(klass, originalSelector, method_getImplementation(replacementMethod), method_getTypeEncoding(replacementMethod)))
{
class_replaceMethod(klass, replacementSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else
{
method_exchangeImplementations(originalMethod, replacementMethod);
}
}
- (void)funDealloc
{
if (self.deallocationDelegate)
[self.deallocationDelegate performSelector:#selector(handleDeallocation:) withObject:self];
[self funDealloc];
}
static char myKey;
- (void)setDeallocationDelegate:(id)deallocationDelegate
{
objc_setAssociatedObject(self, &myKey, deallocationDelegate, OBJC_ASSOCIATION_ASSIGN);
}
- (id)deallocationDelegate
{
return objc_getAssociatedObject(self, &myKey);
}
#end
I ran some test code in my application delegate just to see if it works. I declared an NSMutableArray instance designed to hold NSValue instances derived from the pointers of objects calling -handleDeallocation, which I implement as shown:
- (void)handleDeallocation:(id)toDie
{
NSValue *pointerValue = [NSValue valueWithPointer:toDie];
[self.deallocatedPointerValues addObject:pointerValue];
}
Now, here's a snippet of what I ran. SomeClass is an NSObject subclass with no additional properties or methods.
self.deallocatedPointerValues = [NSMutableArray array];
SomeClass *arsc = nil;
#autoreleasepool {
arsc = [[[SomeClass alloc] init] autorelease];
arsc.deallocationDelegate = self;
NSValue *prePointerValue = [NSValue valueWithPointer:arsc];
BOOL preDeallocated = [self.deallocatedPointerValues containsObject:prePointerValue];
NSLog(#"PreDeallocated should be no is %d",preDeallocated);
}
NSValue *postPointerValue = [NSValue valueWithPointer:arsc];
BOOL postDeallocated = [self.deallocatedPointerValues containsObject:postPointerValue];
NSLog(#"Post deallocated should be yes is %d",postDeallocated);
In this case, it can be verified that the object pointed to by arsc (which stands for auto released SomeClass) has been deallocated due to ending the #autoreleasepool block.
There are several significant limitations to the this approach. One, this cannot work when other messages of retain may be sent to your object that is returned from your factory method. Also, and this should go without saying, swizzling dealloc should only be done in experimental settings, and I think some would argue that it shouldn't be swizzled in testing (obviously it shouldn't be swizzled in production!). Finally, and more significantly, this doesn't work well with Foundation objects such as NSString that have been optimized in ways that it's not always clear whether you are creating a new instance or not. So this is most appropriate, if at all, for your own custom objects.
As a final word, I don't think it's practical to do this really. I felt it was more work than it was worth and is so narrowly applicable as the make spending time learning instruments better to be a far better investment when it comes to memory management. And, of course, with ARC's ascendency, this approach is archaic from the start. Regardless, if you do have need to write such tests, and can work around the limitations here, feel free to adapt this code. I'd be curious to see how it pans out in an actual testing environment.
I commend your dedication to TDD. But memory management is an area where you simply have to follow well-established conventions: "When returning an object, it needs to take care of its own lifetime." My unit tests catch me when I accidentally over-release something, but they won't catch a leak. For that, I rely first on Analyze, then on running the Leaks instrument.
This is one of my method.
- (void)getSearchResultsByKeyword:(NSString *)keyword
searchOptions:(NSArray *)searchOptions
searchGroupsInResult:(NSArray *)searchGroupsInResult
{
_searchKeyword = [keyword retain];
_searchOptions = [searchOptions retain];
_searchGroupsInResult = [searchGroupsInResult retain];
[_searchResultsGroups removeAllObjects];
[_searchResultsGroupsIndexToNameMap removeAllObjects];
_pageNo = 1;
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:SearchResultsRetrievingStartLodingNotification
object:self];
[_dataProvider startGettingSearchResultsByKeyword:self.searchKeyword
searchOptions:_searchOptions
searchGroupsInResult:_searchGroupsInResult
pageNo:_pageNo
delegate:self];
}
In my method I have called retain on the objects which are parameters. So I have owned the object and has increased the retain count. So my problem is, how do I decrease the retain count after the
[_dataProvider startGettingSearchResultsByKeyword:self.searchKeyword
searchOptions:_searchOptions
searchGroupsInResult:_searchGroupsInResult
pageNo:_pageNo
delegate:self];
call. ( [keyword release] or [_searchKeyword release] ) ??
In my header file I have declared the _searchOptions as a private instance and _searchKeyword as a readonly property. In my implementation file, I have released both instances in dealloc.
I ran Analyze tool and it did not show this thing as an issue. But I have a doubt on it.
So, please show me a necessary way to work on this thing.
I'm working on XCode4 and iOS 4.3.
Thanks.
jaydee3's answer is correct. I would add that you really should use #properties with synthesized accessors. Then, instead of setting your instance variables directly, use the accessor methods. That way you can encapsulate all of the memory management of your instance variables in the accessor methods. This has the advantage of being more readable, much less error prone, and makes your code easier to modify in the future.
So, in your .h (or in a class extension in your .m if the properties should be "private"):
#property (nonatomic, copy) NSString *searchKeyword;
In your .m:
- (void)dealloc
{
self.searchKeyword = nil;
[super dealloc];
}
#synthesize searchKeyword = _searchKeyword;
Finally, in your -getSearchResultsByKeyword:searchOptions:searchGroupsInResult: method:
self.searchKeyword = keyword;
instead of
_searchKeyword = [keyword retain];
Now you don't have to worry about releasing or retaining searchKeyword. The setter method generated by the #synthesize directive will take care of it for you. I suggest reading Apple's documentation on Declared Properties.
Since you are assigning to an ivar, you have to retain it. This is correct.
Releasing it within dealloc is also correct. But thats not enough. Two things:
1) It's better to copy strings, rather than retain them. So use _searchKeyword = [keyword copy];. (This is also retained. So the retainCount is 1 after that.)
2) Also there is a problem, when you call your method the second time. That is the point, where you do have a leak. You are assigning a new value to your ivar `_searchKeyword', dismissing the pointer to the old keyword, which is still retained. So before assigning the new one, release the old one also.
Example:
[_searchKeyword release];
_searchKeyword = [keyword copy];
If you copy it, this is good, but if you only retain, it would be even better to do it like that (in case both reference the same object):
[keyword retain];
[_searchKeyword release];
_searchKeyword = keyword;
When there are two objects that are pointers to the same thing, it doesn't matter which one you call release on. The thing pointed at is where the reference count gets decremented.
Given you've released it in one place, and the analyzer isn't complaining, you don't have a problem.
Maybe someone could explain the difference between property:
in .h file
#property(nonatomic,retain) NSString *someString;
#property(nonatomic,retain) NSString *someString2;
in .m file
#synthesize someString = _someString;
or
#synthesize someString2;
what is the difference for _someString and self.someString2 using in controller?
and in dealloc how i should release these property's
[_someString release];
AND
[self.someString2 release];
OR
_someString = nil;
_someString2 = nil;
synthesize someString = _someString;
This says synthesize the property someString but for direct access, use _somestring.
synthesize someString2;
This says synthesize the property someString2 but for direct access, use someString2.
Think of it as if the compiler is generating the iVars for you but in the first case the iVar is called _someString and the second is called someString2
This is a common usage (I recently moved to it) so that when you are dealing with the object directly (such as initialisers or in dealloc, where you should't use self) you can see instantly that when you write _someString = #"aString"; you are not going through the property methods that would apply the memory management types (such as retain, or copy). It used to be common that people would assign values directly, and then wonder why they weren't being retained.
[_someString release];
[_someString2 release];
Is sending the release method directly to the object.
self.someString = nil;
self.someString2 = nil;
Sends release through the property. In this case, There is no difference. There would be a difference if you were allocating objects: for example:
_someString = someOtherString;
Is a leak (except under ARC, which I will come to later), because you are just putting in a new object to the store, without releasing the current object.
self.someString = someOtherString;
does not leak anything, because the sythesized setter will release the current object before setting (and retaining) the new object.
I said I'd come to ARC. In which case you can't call release anyway, so the questions don't arise, but _someString = someOtherString is not a leak, because the compiler will deal with releasing the current object for you.
After:
property(nonatomic,retain) NSString *someString;
property(nonatomic,retain) NSString *someString2;
and:
#synthesize someString = _someString;
#synthesize someString2;
someString is a property backed by the instance variable _someString. Memory retention and release is managed by Obj-C.
Assignments to someString should use the form self.someString within the class, and must use <reference>.someString outside of it. Except within an initializer there should never be any assignments to a plain _someString.
Reading the value can use simply _someString within the class, but self.someString is also valid, and must use <reference>.someString outside of it.
Releasing the value must use the form self.someString = nil within the class, and <reference>.someString = nil outside of it.
someString2 is similar except it is backed by an automatically named instance variable, which happens to be called someString2.
#synthesize someString = _someString; Means you're making a property with a different name then the member variable it's associated with. This is fine. Typically they are same name. Here's an example when that isn't the case. So someString would be your property and _someString is your member variable.
As for [_someString release]; and [self.someString2 release]; what you're seeing is release being called on the member variable of your class(Which is _someString). [self.someString2 release] calls release on whatever the property returns. Keep in mind that properties can do more then just simply get and set. They are methods just like any other you might right.
Also, don't do [self.someString2 release]; Instead do self.someString2 = nil; That will release it on your behalf. That way it nils out the string. That will protect you from accessing bad memory incase the string is actually deallocated.
_someString = nil won't release your property.
In this case _someString and self._someString point to the exact same object, so you can release using either.
[_someString release];
AND
[self.someString2 release];
releases twice, that's wrong. Use
_someString = nil;
_someString2 = nil;
simply sets your ivars to nil, it doesn't release them, so that's again wrong.
Correct: either
self.someString = nil;
self.someString2 = nil;
or
[_someString release];
[_someString2 release];
I'd recommend the first one (dot-notation), as it does the right thing (you don't know what kind of code does a compiler generate when synthesizing your accessors...)
I have a class named SomeClass. in its init I have a lot of lines like:
SomeProperty_ = [[SomeObject alloc] initWithSomething];
While the properties are declared as
#property(retain) SomeObject *SomeProperty;
and defined as
#synthesize SomeProperty = SomeProperty_;
When I allocate objects of SomeClass and later release them, everything works fine and there are no memory leaks. However, when I copy an object of SomeClass and later release it, all the lines like
SomeProperty_ = [[SomeObject alloc] initWithSomething];
are marked as a memory leak in Instruments. this is also correct as I get memory warning and later crash if I use this a lot.
However if I make a method named dealloc like:
-(void) dealloc
{
self.SomeProperty = nil;
[super dealloc];
}
Everything is fine with copies as well and no memory warning or leaks.
I think this is because of my copy implementation:
-(id)copy
{
SomeClass *copy = [[SomeClass alloc] init];
copy.SomeProperty.somePOD = self.SomeProperty.somePOD;
return copy;
}
Where is the problem? what can I do to resolve it without the custom dealloc?
The first things I can think of is:
How your somePOD is set as far as #property(???)
And when you say :
"However, when I copy an object of SomeClass and later release it, all the lines like
SomeProperty_ = [[SomeObject alloc] initWithSomething];
are marked as a memory leak in Instruments. this is also correct as I get memory warning and later crash if I use this a lot."
You are referring to call made in your init method?
Because if your not, you are bypassing a setter and the object that was in that variable before this assignment will leak.
You must either use a custom dealloc method or start using Automatic Reference Counting (ARC).
When you call [[SomeObject alloc] init...], you get ownership of the new object, so you must release the object when you are done with it. Setting self.SomeProperty to nil does the release because you declare the property with the retain attribute.
You do this in your dealloc method if you want to own the SomeObject object until your SomeClass object dies. If you use ARC, it will generate the dealloc method for you.
I see in some sample code that autorelease is used. I am not familiar with the instances when this is required. For example, if I create an annotation object
Header file
#interface someViewController: UIViewController
{
Annotation *annotation;
}
#property (nonatomic, retain) Annotation *annotation;
#end
Implementation file
#implementation someViewController
#synthesize annotation
#end
Question: Is it the correct approach if I initialize my annotation object in the implementation file like this?
self.annotation = [[Annotation alloc] initWithCoordinate:location];
Do I need to set autorelease for this? Or can I just do it the normal way and add the release in the dealloc method?
this is correct:
self.annotation = [[[Annotation alloc] initWithCoordinate:location] autorelease];
because annotation property is declared as a retain property, so assigning to it will increment its retain count.
you will also need, all the same, to release self.annotation in -dealloc.
in short:
init will set retain count to 1;
assigning to self.annotation, will set it to 2;
autorelease will set it back to 1 when the main loop is executed again;
release in dealloc will set the retain count to 0, so that the object will be deallocated);
the best way to think of autorelease is the following, in my opinion: autorelease will "schedule" an "automatic" release for your object at some (near) point in future (typically when the control flow goes back to the main loop, but details are hidden in the hands of Apple).
autorelease is mostly useful in conjunction with init, specifically in the following cases:
when you init a local variable, so that you don't have to release it explicitly before it goes out of scope (the main loop will do that for you);
when you return a pointer to an object you have just created without keeping ownership of it (typical case of the create/make* kind of selectors, the receiver is required to retain it to get ownership);
with properties that retain, when you assign to them an object that they should own uniquely;
with data structures that increment the retain count (NSMutableArray, NSMutableDictionary, etc): you should generally autorelease a newly inited object when you add it to such data structure.
apart from case 2, it is evident that the use of autorelease is meant to improve readability of the code and reduce the potential for errors (meaning that in all of the other cases, you could simply release explicitly your object after the assignment or at the end of the scope).
when using properties, you have always to check whether they are of the retain or assign/copy case; in the first case, assigning a newly inited object to a property generally requires autorelease.
Anyway, I would suggest at least skimming one of the many tutorial on memory management for iOS.
Autorelease is telling the object to release itself before leaving the scope.
Sometimes when you code, you'll encounter something like this
- (void)doSomething
{
if(true)
{
NSString *foo = [[NSString alloc] initWithString:#"foo"];
//Some execution here
[foo release];
}
}
- (void)doSomething
{
if(true)
{
//By doing this is telling to to release foo object before getting out of the scope
//which is similar with above practice
NSString *foo = [[[NSString alloc] initWithString:#"foo"] autorelease];
//Or you can do it this way
NSString *foo = [[NSString alloc] initWithString:#"foo"];
[foo autorelease];
//Some execution carry on, it'll release foo before entering next scope
}
//This is out of the scope
}
Of course, releasing an object doesn't mean deallocating the object.
Sometimes you retain the object so you can still use it outside of its scope.
Judging from your question, if your the object is located within your header file/interface.
You should release it in dealloc method. CMIIW.