Today I see code in which user is releasing the object first and then he is making that object nil. like this
[objectA release];
objectA=nil;
I have read at many books that we should make the object nil while leaving the view and release the object later(in dealloc method of course this method is called after viewWillDisappear or viewDidDisappear).
Now i want to know that which approach is better?
Setting to nil and releasing are two distinct operations.
You release an object to relinquish ownership of it. This is covered in the standard Memory Managemange Guidelines. If you are not familiar with them, you should read them before doing any further iOS programming.
After releasing an object, you should set it to nil if you know that some other code may attempt to access that variable later. This is most common with instance variables.
For example, you may use an instance variable to store some sort of cache:
- (NSArray *)items
{
if (!cachedItems) {
cachedItems = [[self calculateItems] retain];
}
return cachedItems;
}
Later on you may need to clear this cache:
- (void)invalidateCache
{
[cachedItems release];
cachedItems = nil;
}
We need to set cachedItems to nil because our items method may attempt to use it later. If we do not set it to nil, messages send to the (now released) cache can lead to a crash.
So set a variable to nil after releasing it when it can potentially be access by other methods in your class at a later point in time.
I don't think is important set object to nil, but is good to do.
If you do :
objectA = nil;
[objectA release];
You have LOST the memory, and this is a memory leak. If you only do [objectA release], you will release the memory, but the objectA still point to the memory, so if you try to do things like:
if (objectA==nil)
This will return FALSE, because objectA is NOT a nil. But because you do this almost in
- (void)dealloc;
you don't need set it to nil in this function.
If the object is created locally:
I would go with the first approach, it's a common practice to release the object first then assign an nil.
I haven'nt read about your second approach in any book.
If the object is the part of class variable and have retain and #synthesize :
The below will do the both work (first release then assign nil through setter function) at once.
self.object = nil ;
First approach is the way to go for you..
[objectA release];
objectA=nil;
Also making object nil is a good practice (not if you are using it later) because after releasing the object, if I accidentally refers to it again your app will crash. But if you gave nil to the object, and you refer to it later it won't crash in objective C.(Situations similiar gave nullpointerException in languages like java)
ie
[objectA doneSomeTask];
wont crash,even if objectA is nil. As objective C silently ignores refering to nil.
What you have read in books does not work. If you set the object to nil you can not release it later because you can not excess the object then. You should to the first approach.
Best way:
[objectA release]; // sightly sightly faster since less function calls
objectA=nil;
Lazy way:
self.objectA=nil;
it will call:
(void)setObjectA:(ObjectAClass *)objectA
{
[objectA release]; // <-- original value is released
objectA = [objectA retain];// <-- set the point to nil and do nothing since nil
}
Related
Let's assume that we create an instance of class var foo: Foo? = Foo() on the main thread and we call some time consuming instance method bar of Foo on another thread, after a short time we set foo to nil on main thread. What happens with the execution of bar, in my understanding bar should still continue its execution since invoking instance method implicitly passes self as the first argument, so even those the last explicit ref to foo was broken we still have a ref inside of a method and it should be good. But then I found this stackoverflow post which completely breaks my understanding. So, can somebody confirm/deny the fact that object cannot be deallocated during its method execution
Short answer is that your belief is correct, and you're looking at a question that's not relevant to Swift.
Your link is to non-ARC Objective-C. Swift always uses ARC, and ARC is very conservative about retains. Consider the following Objective-C call:
[target runMethod: parameter];
Under ARC, this is (conceptually) transformed into:
[target retain];
[parameter retain];
[target runMethod: parameter];
[parameter release];
[target release];
retain and release are atomic, thread-safe calls.
A similar behavior exists in Swift. Because of this, as a general rule (in the absence of Unsafe), a variable cannot "disappear" while you'll holding onto it.
This is the implementation detail. The better way to think about it is that by default variables and parameters are strong, and an object cannot be destroyed while there is a strong reference. This matches your understanding.
Prior to ARC, though, you needed to insert extra retains and releases yourself to protect against this kind of situation, and it was very common not to. (Prior to 10.6, most ObjC was single-threaded.)
Even without threads, there are ways this can go astray without ARC. Since callers often didn't immediately retain returned values if they only needed them temporarily, it was possible to get dangling pointers even without multiple threads. For example, with a trivial accessor with no memory management, this can crash:
NSString *name = [person name];
[person release];
[self doSomethingWithName: name];
This is why you often see old ObjC getters written in the form:
- (NSString*) title {
return [[title retain] autorelease];
}
This made sure that the returned value would survive until the end of the event loop even if self released it or self was deallocated.
Swift does similar things via ARC, but as the name suggests, it's all automatic.
I see some code with
#property (nonatomic, readwrite, retain) id something;
And they synthesise it:
#synthesize something = something_;
And in the constructor:
self.something = #"HELLO!";
I assume that, the above line effectively retains that string.
But then, in their dealloc method, they do this:
[self setSomething:nil];
I guess that it is fine, because I imagine that when you set a property to nil, the old value is released. But then, I noticed that all the other classes they did had something like
[something release];
Instead, so I'm no longer sure. Are both ways correct?
Short answer: Use ARC. It takes care of this stuff for you. It's much less error-prone, and just as fast as manual reference counting.
Longer answer:
If you use retained properties, then yes, setting the property to nil is the correct thing to do.
like this:
self.something = nil;
That works because the setter for a retained property first releases the old value, then retains the new value and assigns it to the property's iVar. Since the new value is nil the retain does nothing.
If in your second example:
[something release];
something is the iVar for a property, this code will cause a future crash if it is called from anywhere but in the code for the object's dealloc method. The reason is that this releases the object, but does not zero out the iVar. Later, when the object that has a something property is released, its dealloc method fires. The code in the dealloc method should attempt to release the object's retained properties. Sending release to an object that was already deallocated causes a crash.
In your case, you are asking about the code in a dealloc method. In dealloc, calling [something release] and setting the property to nil have the same result of releasing the object. Invoking the setter is probably safer, though, since custom setters sometimes have other code with additional "side effects." Since you're writing the dealloc method, you should be the author of the class, and should be aware of any special code in the setter method.
Now, if something is an instance variable, not a property, the correct thing to do is
[something release]
something = nil;
EDITED 5 June 2014 to discuss the case of code in a dealloc method.
Better to use [something_ release]. This won't cause setter to be called, which otherwise could cause some actions to be performed that are undesired in dealloc.
Both are correct, [self setSomething:nil]; will be better, when something is released to 0 retainCount then dealloc. This prevent using something from crash with BAD_EXE.
As mifki said, setter to be called if use [self setSomething:nil]; so this is depended on what have you done in setter method, a good setter should care about set value to nil, and deal with the case properly, and will not be undesired.
And even if setter method implement can't be cared to set to nil always, the better release style should be :
[something_ release], something_ = nil; //this should be safely release always
I was wondering how you would release a singleton
+ (DSActivityView *)activityViewForView:(UIView *)addToView withLabel:(NSString *)labelText width:(NSUInteger)labelWidth;
{
// Not autoreleased, as it is basically a singleton:
return [[self alloc] initForView:addToView withLabel:labelText width:labelWidth];
}
When analysing this using the analyse tool i get the following error :
Potential leak of object on line 90. which is the line that returns.
I have tried autorelease that solves the error message problem but im not convinced its the right solution since i read that autoreleasing singletons is not good. Would someone be able to assist me in identifying how best to release this object?
Thanks
The reason why the analyzer gives you the warning is, basically, the method name:
+ (DSActivityView *)activityViewForView:(UIView *)addToView withLabel:(NSString *)labelText width:(NSUInteger)labelWidth;
according to Objective-C conventions, all method names starting with "create"/"new"/... return a retained object; your method falls under the category of convenience constructors, which are expected to return autoreleased objects, hence the warning.
On the other hand, you say this is a singleton, but in fact it is not. So, you could possibly end up calling this method more than once and thus have an actual leak. A basic way to make your method safer (and more singleton-like) is:
+ (DSActivityView *)activityViewForView:(UIView *)addToView withLabel:(NSString *)labelText width:(NSUInteger)labelWidth;
{
static DSActivityView* gDSActivityViewSingleton = nil;
if (!gDSActivityViewSingleton)
gDSActivityViewSingleton = [[self alloc] initForView:addToView withLabel:labelText width:labelWidth];
return gDSActivityViewSingleton;
}
This would both make the analyzer relax and give you more safety in front of the possibility of misuse of the method.
Use autorelease. There's no reason not to. Basically ownership of the object belongs to the object, so you're never going to be able to manually release it. As its a singleton it doesn't matter if you don't own it because presumably next time you call it and need it in scope you'll use another convenience method and it will get instantiated again.
If you want to have ownership of the object then you will need to instantiate it as normal and then you will be able to retain and release it.
Also, read sergio's edit about it not being a "proper" singleton. :p
Also, if you can, convert to ARC and you won't have to worry about this!
U are doing it wrong. Consider:
If you calling activityViewForView multiple times, you won't get get the same object over and over again. It only would initialize a new object and give you the pointer to it!!!
To make this thing a singleton, you have to store the created object in a constant variable and make sure, you have a reference to this object all the time your app is running (for instance declare your pointer to this object in appDelegate).
Then every time you call activityViewForView you have to check the constant variable if it is pointing to a valid object. If so, return the valid object, if not, create it and store it in your constant static variable (creation is done only once).
If you do use ARC you're all set. If not, release your object (use dealloc method)
The XCode analyzer tells me there is a problem at line 4 — return [originalError copy]; — but I don't see it. Help me please?
- (NSError *)errorFromOriginalError:(NSError *)originalError error:(NSError *)secondError
{
if (secondError == nil) {
return [originalError copy];
}
// ...
}
The problem description is:
Potential leak of an object allocated on line 203
Method returns an Objective-C object with a +1 retain count (owning reference)
Object returned to caller as an owning reference (single retain count transferred to caller)
Object allocated on line 203 is returned from a method whose name ('errorFromOriginalError:error:') does not contain 'copy' or otherwise starts with 'new' or 'alloc'. This violates the naming convention rules given in the Memory Management Guide for Cocoa (object leaked)
Potential null dereference. According to coding standards in 'Creating and Returning NSError Objects' the parameter 'error' may be null
The third issue seems to suggest I should either change the name or the behaviour of the method further. Any suggestions on that? The method is derived from the errorFromOriginalError:error: method described in Apple's Core Data Validation document. Its purpose is to combine originalError and secondError so that secondError is a sub-error of originalError.
My addition tries to ensure that the method still works if there is no actual secondError. Since a new error object is created if secondError is not nil, I wanted to recreate that in the case displayed above by simply copying the error object.
You are making a copy of originalError, but your function name implies that the returned object will be autoreleased. Try
return [[originalError copy] autorelease];
[originalError copy] creates a new object with a retain count set to 1. It would then be the responsibility of the calling method to release that object. If you're doing this then it isn't necessarily a problem, but it's probably a better ideas to autorelease it.
ie
return [[originalError copy] autorelease];
I've people who use [variable release] and some other times variable = nil to clean up memory?
When do you use each one? and what are the differences?
variable = nil; will not release memory. self.property = nil; will release memory if [self setProperty:nil]; would, for example a synthesized property with the retain attribute. Calling [variable release]; will always release one reference of an object.
Depends on what you mean by "clean up memory".
release is the only thing that frees dynamically allocated memory allocated by alloc. alloc should always be paired with a call to release or autorelease somewhere.
Setting a varible to nil does not necessarily free any memory (see drawnonward's answer), and can be a source of memory leaks.
When you see a variable set to nil, it's about preventing it from accidentally being used later after its memory has been freed (this can cause crashes). While you can always set a variable to nil after a call to release, it's somewhat a matter of style when it's actually necessary. For example, you don't often see variables set to nil in the dealloc method of a class, since by that point an object won't be able to accidentally misuse such a variable anymore, since it's being nuked.
If a property is set to retain, then these 3 are equivalent:
[self setProperty:nil];
self.property = nil;
[property release]; property = nil;
In each case, the object will be released, and then set to nil so that all access to the object from then on will not be allowed. "nilling" the instance variable is handy since it ensures you can only ever release the object once in this context because calling self.property = nil twice will do nothing the second time, but calling [property release] will release the object twice even though you likely only retain it once.
Most of the time I find it least bug prone to let retain properties do their thing and try to stay away from explicit retain and release calls most of the time.