A more definitive answer on when to release an object - objective-c

I know this has been answered before (sort of) but I've been reading conflicting answers on exactly when or when not to release an object that has not been specifically subclassed via an allocation.
For example, if I do the following:
#property (..., retain) NSMutableArray *myArray;
or in general,
#property (some retain attribute - strong, weak, retain) type myObject;
After synthesization, If I do nothing else to myObject (no allocation or even forget to use it), are there any cases in which I'm still responsible to release it?

There are two totally different answers depending on whether or not you're using ARC. Since the ARC environment is pretty straight forward, I'll just answer from a pre-ARC perspective. The main thing to understand is that all of the talk around property retain semantics is just a distraction from the main point: If you take ownership, you must relinquish it. Relinquishing ownership is done via -release. So, what you need to understand is "What counts as taking ownership?"
By convention, any time you send a message to class that contains any of [new, alloc, retain, copy], you now own that object. The compiler generates setter methods for Objective C Properties depending on the ownership policies you specify. For example...
#property (..., retain) NSMutableArray *myArray;
#synthesize myArray = _myArray;
This generates a method that looks like this1:
- (void)setMyArray:(NSMutableArray *)myArray
{
// This is oversimplified, just to illustrate the important point.
// Again, this is NOT the way a setter would actually be synthesized.
[_myArray release];
_myArray = [myArray retain];
}
So now, when you say something like self.myArray = someArray, you know you've sent a retain message to someArray, and you're responsible for releasing it later. The ideal way to do that is to say self.myArray = nil, because it releases the old value before retaining nil. Note that it's also perfectly safe to send that message, even if you never set anything to the myArray property, because sending messages to nil is okay. That's why it's common to always set owned properties to nil when you're done with them, regardless of how they're being used.
1 For a study on how accessors should actually work, see this article.

Related

Objective-C/ARC ivar vs property [duplicate]

This question already has answers here:
Property vs. ivar in times of ARC
(2 answers)
Closed 8 years ago.
I've been up and down the Google and the Stack and read many articles if not outright debates over ivars and properties. But still, even after all this reading I remain confused.
I understand ivar's are private and properties are typically used to expose (well) class properties. But I understand properties to be more than that, they contain Getters and Setters and when it comes to memory management (even under ARC) I can see the benefit to using them exclusively.
But my question is; does any of this matter anymore now that we have ARC? (see comment in example code below).
Consider:
#interface MyClass
#property(strong) NSMutableArray *myArray;
#end
#interface MyClass
-(instancetype)init {
if (self = [super init]) {
self.myArray = [NSMutableArray array];
// OR
// Will this NOT call the Setter? Hence, leading
// to possible memory leak issues?
_myArray = [NSMutableArray array];
}
return self;
}
#end
self.myArray = [NSMutableArray array]; is considered bad form in init. You should avoid the use of setters entirely in your initialisation. The risk is that a subclass may override the method, in which case you're calling a method on a class that hasn't been inited yet (because it's got only as far as initing you). See the obligatory Mike Ash citation.
_myArray = ... does not call the setter and is therefore the correct form for an init regardless of whether you also have a property.
ARC makes correct memory-management all but a none issue. The debate is exclusively what you want technically to expose and how adaptable you want your internal code to be. I tend to prefer explicit instance variables because that shouts 'private implementation detail'.
Back in the old days of Objective-C, you had ivars, and if you wanted to let some other class set or read them then you had to define a getter and a setter.
As I explained to you, with properties you get the setter and getter for free (almost!) along with an instance variable. So when you define a property, you can set the atomicity as well as assign/retain/copy memory management semantics.
Most people leave the ivar name the same as the property name, but it can be made to be something else when you write your #synthesize statement (i.e., #synthesize foo=_foo; means make an ivar named _foo for the property foo).
Note that as of Xcode 4.6, you do not need to use the #synthesize statement - by default will the compiler prepend the ivar's name with _. So #synthesize is no longer recommended by Apple for new code.
In both cases the assigned value will be retained, since you are assigning it to a strong variable. (Strong is the default for variables that reference object instances)
In the first example the method -setMyArray: will be called, which in the case of a generated setter will store the value to _myArray. In the second case, -setMyArray: will not be called.
For the given code the object already assigned to _myArray will have its reference count properly decremented when the _myArray is set again. (The existing strong reference to the object will be deleted.)
That first call will call the setter while the second will not, however both calls will overwrite the ivar _myArray. For example, if you did self.myArray = #[#"Hello"]; and then _myArray = #[#"World"], printing out both self.myArray or _myArray will print #[#"World"].
If you instead write your own method -(void)setMyArray;, It could possibly do different things, but then you also won't get the private ivar _myArray without declaring it yourself.

Can I send release to an ivar without alloc/init?

I have an NSString property:
.h file
#property (nonatomic, retain) NSString *str;
.m file
#synthesize str;
What is the retain count of str without alloc/init? Can I [str release] in a method?
I am assuming your new to the concept of memory management, so I would advise to have a read of the apple docs around memory management before you continue with your development.
Basic Memory Management Rules
You own any object you create.
You can take ownership of an object using retain.
When you no longer need it, you must relinquish ownership of an object you own.
You must not relinquish ownership of an object you don't own.
I will refer you to the Memory Management Policy in the apple docs for a good understanding of memory management
So when you have read the apple docs you will fully understand what is going on in your code, but if you don't this is what is wrong. You can not release an object that you don't have ownership of. This violates point 4 of the Basic memory management rules in the apple docs. To take ownership of this object you must do str = [[NSString alloc] init]; (This is not needed with ARC) in your .m file.
My recommendation though would be to read up about ARC it is a lot better then handling the memory management yourself. As you would no longer have to do things such as [str release]; once you wanted to relinquish ownership of the object as it is done automatically.
You cannot release an object that has not yet been allocated.
Use ARC where possible, and read about changes to Objective-C in the past 2 years: it is no longer necessary to synthesize variables declared in .h in your .m
You shoudn't release an object that has not yet been allocated. But if you do it it means you are sending a message to a nil object. That is safe because a message to nil does nothing and returns nil, Nil, NULL, 0, or 0.0.
Yes you can release this object. Whenever you send alloc, copy, new, retain any of these message to an object. It's retain count increased by 1. And you become the owner of that object. So you must release the object to relinquish the ownership.
And when you use ARC the compiler do it for you. Hope it helps.
As its a retained property you can do self.str=nil; instead of [str release] safely.
You can not do [str release] as we can release only what we alloc and init by ourself and its not init yet.

ARC, non-ARC, and inheritance

I haven't used ARC yet other than to deal with it when it forces it's way into a project via 3rd party code. I've read all the ARC docs but haven't seen an answer to this question:
If I have a class that's defined in a module compiled with -fobjc-arc, can I derive a new class from this in a module that is NOT ARC-enabled?
In my mind it should work fine as long as the derived class doesn't attempt to touch any ivars in the root class. It seems to me that even having a dealloc method that calls [super dealloc] would be fine in the derived class.
And, what about the other way around? Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
Bonus points: are there any gotcha's when mixing ARC and non-ARC code that I should make myself aware of?
There are no issues that I am aware of. You have to realize that ARC is something like a source code preprocessor, adding the memory management calls for you during the compilation. When you arrive at the linking phase, you can’t really tell ARC code from non-ARC code. (This is probably an over-simplification, but one that should work for your purposes.) If your derived class has correct memory management and the super class has correct memory management, the result will work fine.
About the only difference I can think of is handling of weak properties. But I don’t know enough about those to say if it’s possible to arrive at buggy code using some combination of ARC and MRC code with weak properties.
This was a comment, but having thought about it I want to expand what it said.
Have you tried inheriting an ARC class from a normal subclass? My thoughts (without having tried it either) is that this will not work. Firstly, if the ARC class has public properties or ivars using ARC keywords, like weak I think you will get errors during compilation from the header file. Secondly, I don't know how the dealloc would work. Do you need to call [super dealloc] or not? I don't know.
Anyway, if your superclass is ARC, why would you not use ARC in any subclasses? There's no advantage to doing that at all.
Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
I was going to say that won't work either, but I would have been wrong. Virtually everything has to inherit from NSObject which is manual reference counted.
Yes, you may both implement non-ARC ancestor from ARC parent class, and ARC ancestor from non-ARC parent class.
Actually, ARC is a syntax sugar, or you may say, is just preprocessor which analyzes your source code at compile step and inserts appropriate [release] and [retain] calls to your code. At runtime level nothing is changed (except for the weak properties).
ARC means the compiler takes care of memory management, non-ARC means you take care of it, but in both cases memory management works exactly the same way:
If an object must stay alive, its retain counter is increased (that's what retain does)
If an object is not needed anymore, its retain counter is decreased before the reference to it is lost (that's what release does)
If you are done with an object but it must not die yet, e.g. as you need to return it as a method result (and you don't want to return a dead object), it must be added to an autorelease pool that will decrease its retain count at a later time (that's what autorelease does, it's like saying "call release on that object at some future time.")
Newly created objects have a retain count of 1.
If the retain count reaches zero, the object is freed.
Whether you do all that yourself or the compiler does it for you, it plays no role. After compilation, these methods are being called, also with ARC, but with ARC the compiler has decided for you when which method is called. There is some extra magic, e.g. ARC doesn't always have to add objects to autorelease pools when returning them as method result, this can often be optimized away, but you don't have to care as this magic is only applied if the caller and the called method both are using ARC; if one of them isn't, then a normal autorelease is used (which still works in ARC exactly as it used to).
The only thing you must take care of is retain cycles. Whether you use ARC or not, reference counting can't deal with retain cycles. No difference here.
Pitfalls? Careful with Toll Free Bridging. A NSString * and a CFStringRef are in fact the same thing but ARC doesn't know about the CF-world, so while ARC takes care of the NSString, you must take care of the CFString. When using ARC, you need to tell ARC how to bridge.
CFStringRef cfstr = ...;
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
// NSString * nsstr = [(NSString *)cfstr autorelease];
Code above means "ARC, please take ownership of that CFString object and take care of releasing it as soon as you are done with it". The code behaves like the code shown in the comment below; so careful, cfstr should have a retain count of at least one and ARC will release it at least once, just not yet. The other way round:
NSString * nsstr = ...;
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr;
// CFStringRef cfstr = (CFStringRef)[nsstr retain];
Code above means "ARC, please give me ownership of that NSString, I'll take care of releasing it once I'm done with it". Of course, you must keep that promise! At some time you will have to call CFRelease(cfstr) otherwise you will leak memory.
Finally there's (__bridge ...) which is just a type cast, no ownership is transferred. This kind of cast is dangerous as it can create dangling pointers if you try to keep the cast result around. Usually you use it when just feeding an ARC object to a function expecting a CF-object as ARC will for sure keep the object alive till the function returns, e.g. this is always safe:
doSomethingWithString((__bridge CFStringRef)nsstr);
Even if ARC was allowed to release nsstr at any time as no code below that line ever accesses it anymore, it will certainly not release it before this function has returned and function arguments are by definition only guaranteed to stay alive until the function returns (in case the function wants to keep the string alive, it must retain it and then ARC won't deallocate it after releasing it as the retain count won't become zero).
The thing most people seem to struggle with is passing ARC objects as void * context, as you sometimes have to with older API, yet that is in fact dead simple:
- (void)doIt {
NSDictionary myCallbackContext = ...;
[obj doSomethingWithCallbackSelector:#selector(iAmDone:)
context:(__bridge_retained void *)myCallbackContext
];
// Bridge cast above makes sure that ARC won't kill
// myCallbackContext prior to returning from this method.
// Think of:
// [obj doSomethingWithCallbackSelector:#selector(iAmDone:)
// context:(void *)[myCallbackContext retain]
// ];
}
// ...
- (void)iAmDone:(void *)context {
NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context;
// Use contextDict as you you like, ARC will release it
// prior to returning from this method. Think of:
// NSDictionary * contextDict = [(NSDictionary *)context autorelease];
}
And I have to real big gotcha for you that are not that obvious at first sight. Please consider this code:
#implementation SomeObject {
id _someIVAR;
}
- (void)someMethod {
id someValue = ...;
_someIVAR = someValue;
}
This code is not the same in ARC and non ARC. In ARC all variables are strong by default, so in ARC this code behaves just like this code would have:
#interface SomeObject
#property (retain,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Assigning someValue will retain it, the object stays alive! In non-ARC the code will behave like this one:
#interface SomeObject
#property (assign,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Note the property is different, as ivar's in non-ARC are neither strong or weak, they are nothing, they are just pointers (in ARC that is called __unsafe_unretained and the keyword here is unsafe).
So if you have code that uses ivars directly and doesn't use properties with setters/getters to access them, then switching from non-ARC to ARC can cause retain cycles in code that used to have sane memory management. On the other hand, moving from ARC to non-ARC, code like that can cause dangling pointers (pointers to former objects but since the object has already died, these point to nowhere and using them has unpredictable results), as objects that used to be kept alive before may now die unexpectedly.

How do you tell whether you need to release an object?

Can you describe the naming convention difference between a method that returns an object it has allocated for the caller (and that the caller should release), and a method that returns an autorelease object?
If you declare a property with a retain attribute, do you need to release the property before you set it to nil?
What does the #synthesize directive do?
From apple documentation
You only release or autorelease objects you own.
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message.
You use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (to understand when this will be, see “Autorelease Pools”).
Your second two questions are related. All that #synthesize does is to generate additional methods for your implementation file. The arguments to #property (nonatomic, retain) NSString* myString; define the behavior of the generated methods. For example, if you declare a property as retain, the setMyString generated method will retain its argument.
Nonatomic is important because properties, by default, are threadsafe. If you don't need thread safety, you can remove a lot of overhead in your accessor methods.
Finally, the implementation of a retain property is
- (void) setMyString:(NSString*)newString {
[newString retain];
[myString release];
myString = newString;
}
So, saying self.myString = nil effectively releases myString for you. Many people advocate using self.property = nil for retained properties, as opposed to [property release], though I think it just comes down to personal preference.
A good source for memory allocation is listed below by Aaron.
Regarding #synthesize:
Say you have a property P, what you will have to do is write a getter and a setter for it. There are a few common approaches, one of which is that you retain that object when you set that property and release the old value. E.g:
- (void)setP:(PClass *)value
{
[value retain];
[_pInstanceVariable release];
_pInstanceVariable = value;
}
Since this is a very common piece of code, the compiler can automate it for you, if you specify the retain keyword in property declaration and then do the #synthesize in you implementation. The compiler will generate the above mentioned code which means your code will be a lot cleaner without tedious repeating parts.
Same holds true for getters, unless you want something more complex than:
- (PClass *)p
{
return _pInstanceVariable;
}
the #synthesize will do the job
memory allocation information and naming can be found here
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
synthesize is documented here
http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW17
The apple website has excellent documentation, I would recommend searching there first.

What's the purpose of an ivar when a property exists?

The following doesn't complain at compilation nor runtime about no name ivar. So why is it so common to see an ivar and #property/#synthesize.
#interface PropTest : NSObject
{
}
#property (retain) NSString *name;
#end
#implementation PropTest
#synthesize name;
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
PropTest *p = [[PropTest new] autorelease];
p.name = #"Hello, World!";
NSLog(#"%#",p.name);
[pool drain];
return 0;
}
This code prints
Hello, World!
In fact, if i access p->name, i get a warning:
warning: instance variable 'name' is #private; this will be a hard error in the future
which indicates that an ivar is created for me if one doesn't exist.
If that's true, what's the point of creating the ivar manually (ignoring the obvious, that there are sometimes valid reasons for not using the g/setter accessor)?
Or asked differently, should i only ever create an ivar for a property when i need to bypass the accessors?
Synthesized ivars (the ability to not manually declare ivars) are a feature of the new Objective-C runtime, which still isn't being used on all systems. For 32-bit Macs (and, until recently, the iPhone simulator), you have to manually declare ivars. If you're only targeting systems with the new runtime, there's no reason to manually declare ivars.
eman's answer is correct overall, but there is one reason to still declare ivars even in the new runtime: Apple discourages synthesized accessors in init and dealloc methods. Essentially, getters and setters are allowed to have side-effects other than just setting a variable. In particular, they could trigger KVO notifications. With an ivar to talk to, you can just send release and be done with it. But if all you have is a property, your only choice is to set it and hope you avoid any unfortunate interactions.
I'm not sure how big a problem this is in practice, to be honest. I've just superstitiously avoided it, even though I secretly doubt it would cause a problem in most cases. But Apple does make a point of this in the docs, so I assume there is some reason to be concerned.
Two not-so-good-but-necessary reasons to make sure properties are backed up by ivars:
For some reason the XCode debugger doesn't show properties that don't have corresponding ivars explicitly declared.
It seems to me that under some circumstances using #property without an ivar can hide other ivars, resulting in compilation errors (see Why does a subclass #property with no corresponding ivar hide superclass ivars? )
Unless I've got the wrong ends of a couple of sticks here, I think the use of #property without explicit ivars may lead to annoyances not warranted by the convenience.