Is it safe to assign a property to the result of an autoreleased initializer while using ARC? - iphone

Let's say I have a strong property like so:
#interface Foo
#property (strong, nonatomic) NSArray *myArray;
#end
And, in my initializer, I set myArray like so:
myArray = [NSArray array];
Is this safe? Will ARC take care of properly retaining myArray for me?
The reason I ask is that I have a project where myArray isn't properly retained in this scenario, and I get a bad memory access down the road.
But, if I use
myArray = [[NSArray alloc] init];
then all is well.

Yes, ARC will automatically retain it for you.
The way to think of ARC is this: If you have a strong pointer to an object, then it is guaranteed to stay alive. When all pointers (well, all strong pointers) to an object go away, the object will die.
From the description of your problem, it sounds like ARC isn't properly enabled in the file where you're executing that code. Regardless, I'd recommend running your app with Instruments, using the "Zombies" template. That will let you see the full retain/release history of that object, and you should be able to figure out where things are going wrong.

Related

Objective-C - allocation/initialization of an object with ARC

I was wondering if I can directly alloc, init an ivar now with ARC (Because if I remember well it wasn't possible without ARC because it would leak memory no) ?
Example (consider an ivar declared like this) :
#property (nonatomic, strong) NSArray *myArray;
#synthetize myArray = _myArray;
And then do
self.myArray = [[NSArray alloc] initWithObjects:object1, object2, nil]; //I know I could directly use [NSArray arrayWithObjects:...] but that's the purpose of my question
Yes.
The only difference between using alloc/initWithObjects: and arrayWithObjects: is that the former leaves you with a retained object, while the second doesn't. If for some reason you wanted to use the former to initialize a property, you'd want to add a call to autorelease to avoid a leak. So you'd do this:
self.myArray = [[[NSArray alloc] initWithObjects:foo, bar, nil] autorelease];
You're correct that with ARC, the compiler will take care of adding that for you, so you can now just say:
self.myArray = [[NSArray alloc] initWithObjects:foo, bar, nil];
It would, if you didn't release it on your dealloc method. With ARC you are responsible for the allocation. In the dealloc method, using ARC, you can still release resources using self.ivar=nil (but ARC is already doing that automatically for you), but not using the word release explicit. Also, ARC does not allow you to call [super dealloc].
You can still alloc and retain. The object lifecycle remains the same, i.e. objects get release when reatin count drops to 0. All that ARC does for you is place the objects in an autorelease pool and correctly release it, where you should have done. You can still override dealloc.
You can find good article about ARC here

Why create a variable rather than direct assignment?

This is a basic question, and I'm not really sure what to search for to see if its been asked before.
In a lot of examples, I've seen property assignments handled like this:
NSArray *tempArray = [/*some code to get array*/];
self.propertyArray = tempArray;
[tempArray release];
Why not just do:
self.propertyArray = [/*some code to get array*/];
What's the difference between the two?
This answer is assuming your not using ARC.
The first code snippet, is the way Apple recommends initializing a property as long as you are doing this in any method besides init. You'll notice Apple code snippets do this a lot. It makes it much easier to manage your memory, and in my opinion it makes it easier to read.
NSArray *tempArray = [[NSArray alloc] initWith....]
self.propertyArray = tempArray;
[tempArray release];
The second code snippet you have could potential lead to a memory leak depending how you set up the NSArray.
This would be a leak. The propertyArray would have an retain count of 2. After you release the instance variable in dealloc, you still have a retain count of 1. That is a leak.
self.propertyArray = [[NSArray alloc] initWith...];
This would be okay, because they both are being autoreleased, which would give you a retain count of 1. As, long as you release the instance variable in dealloc.
// Class Method so autoreleased
self.propertyArray = [NSArray arrayWith....];
// Explicitly declaring autorelease
self.propertyArray = [[[NSArray alloc] initWith.....] autorelease];
It's simply just a matter of preference. I prefer the first way, I think it is easier to to read and follow.
Edit (with ARC):
All these methods would be acceptable with the exception of the release statement and autorelease statement.
[tempArray release];
ARC automatically takes care of the memory management for you, so you do not have to explicitly release them. This is the benefit of ARC, you can create as many objects as you want without the headache of trying to figure out where to release them.
Also, your property would be different. You must either use strong or weak, and not retain. In this case strong would be the solution.
#property (nonatomic, strong) NSArray *tempArray;
In the second example, you don't release the object, which is retained by the property, so you have a memory leak.
self.propertyArray = [[SomeClass alloc] init];
// ^ no release
With ARC, the two statements are equivalent in practice (although you would have to omit the release call for it to actually compile in ARC).
In a manual managed memory scenario, you would leak tempArray in the second ("direct assignment", which it isn't because you're calling a property setter not setting an ivar) example, as you do not have a release call on tempArray to balance it's alloc/init.
The the useful distinction is reduced to expressiveness, the ability to debug, and ultimately the programmers personal preference.
Your first example is the way it was done before the advent of automatic reference counting (ARC). The second example works fine under ARC. Unless you have to do it the old-fashioned way, select ARC for all your projects.
Code like that most likely means that somebody wanted an ability to debug it easier. Basically if you have a separate variable, you can print it out in the debugger without triggering (possibly custom) property setters and getters.

How to understand which property is suitable for NSDictionary eg. retain or assign?

now i using
#property (nonatomic, retain) NSDictionary *currentAttribute;
if i use copy or assign instead of retain is it more difference in memory performance?
Declaring it copy would mean you get an entirely new NSDictionary object for use with your class. If it's quite a large dictionary this can be a performance hit; not very noticeable, but significant anyway. By retaining it, you simply give your class its own pointer to the same NSDictionary instance.
Declaring it assign puts your application at risk of crashing in case the NSDictionary is autoreleased. If it ends up in the pool and gets deallocated because the pool reduced its retain count to 0, your class won't get to access it anymore, causing a crash.

iPhone - initialising variables using self

So, let's say you have a local variable NSArray *myArray declared in your class header file.
You then write #property (nonatomic, retain) NSArray *myArray also in your header file.
In your .m file, you write #synthesize myArray.
All very standard so far. You now have a variable myArray, which can be accessed through setters and getters synthesized by Apple.
A little bit later, you initialise your variable.
NSArray *anArray = [[NSArray alloc] initWithObjects etc etc...];
self.myArray = anArray;
[anArray release];
So now myArray is pointing to an array in memory, which has a release count of one (if I'm not mistaken).
My question is, why can't we write
#property (nonatomic, assign) NSArray *myArray;
#synthesize myArray;
..and then by initialisation write
self.myArray = [[NSArray alloc] initWithObjects etc etc...];
This has TOTALLY confused me ever since the first time I saw it. Is there a technical reason for this? Or moral? ;-) Or theoretical?
Any help would be MUCH appreciated...
Cheers
Karl...
One of the points of properties is to ease us from having to think about memory management ourselves. Making the property assign and then assigning a retained object into it kind of defeats the purpose of using the property.
It's really simple to do:
#property (nonatomic, retain) NSArray * myArray;
#synthesize myArray;
self.myArray = [NSArray arrayWithObjects:etc, etc1, etc2, nil];
And then all the memory management is taken care of for you.
You can.
I mean, it's what I'm doing in my program because I don't like using retain property ^^
It doesn't work ? what is the error ?
By the way you can just write
myArray = [[NSArray alloc] initWithObjects etc etc...];
You can write:
self.myArray = [[[NSArray alloc] initWithObjects etc etc...] autorelease];
(note the addition of the autorelease)
Though it would be simpler to write:
self.myArray = [NSArray arrayWithObjects etc etc...];
Purists might argue that you shouldn't put things into an autorelease pool unless you really need to, however if it makes your code simpler I say go for it, the performance overhead is negligible in many/most cases.
If you use an assign property instead, you need to make sure you release the old contents of myArray yourself, which negates much of the advantage and simplicity.
Memory management in Cocoa (and Cocoa Touch) is very strongly based on conventions. One of those conventions is that objects take ownership of other objects they need to keep around, which means that they must properly retain (to claim ownership) and release (to relinquish ownership) those objects. If you make it an assign property and require every caller to handle the memory for you, this violates the memory management conventions.
It's also poor program design, because rather than have one place (the setter) that is concerned with managing that property, instead you spread the responsibility to every place that accesses the property. Clear separation of concerns is one of the most important aspects of design.
In short: You can do it the way you're asking about. It's just worse in every respect. It violates the assumptions Cocoa makes, it makes bugs more likely, it complicates your design and it bloats your code.
However, in cases where you're setting properties of self, you can do something like what you want. Instead of writing self.someProperty = [[NSString alloc] initWithString:#"Foo"], you can just write someProperty = [[NSString alloc] initWithString:#"Foo"] (assuming someProperty is the underlying instance variable). This is, in fact, the normal way to do it in an initializer method or a dealloc method. This allows you to simply assign the variable in the internal implementation of your class without requiring everybody who uses the class to do the class's memory management for it.
The short answer is that using assign will probably result in memory leaks. Unless you're very careful.
By declaring the array property as retain, you are indicating that the object should take ownership of the array by sending it a retain message and, more importantly, that it should send it a release message when it is no longer interested in keeping the array around. When you use assign, the object won't send the array any retain or release messages. So, in the example you give, there isn't a problem YET. You've created an array with a retain count of one (conceptually) and given it to your object. In this case, the array hangs around in memory with a retain count of 1 just as it would have if you'd used the retain attribute when declaring the property.
The problem comes when you want to change the value of myArray. If your property is declared with retain, an assignment will do something like this:
- (void)setMyArray:(NSArray *)newArray {
if (myArray != newArray) {
[myArray release]; // Old value gets released
myArray = [newValue retain];
}
}
The old myArray gets sent a release message indicating that the object is done with it. If the retain count of myArray drops to zero, it will get deallocated and its memory reclaimed. If the property is declared with assign, this basically happens:
- (void)setMyArray:(NSArray *)newArray {
myArray = newArray;
}
The object forgets about the array at myArray without sending it a release message. Therefore, the array previously referred to by myArray probably won't get deallocated.
So, it's not the assignment that's a problem. It is the failure to release the array during reassignment that will cause the memory leak. This might not be a problem if another object owns the array.
If another object owns the array, and the array is just being referenced by myArray, that other object is in charge of making sure the array stays around as long as myArray needs it and of releasing the array when it's no longer needed. This is the pattern typically used for delegates. You then have to be careful that you don't access myArray after that other object has released the array it references.
Essentially, this comes down to the question of who owns the array referenced by myArray. If another object owns it and will handle retaining and releasing it as needed, it's perfectly okay for your object to simply reference it. However, if your object is the owner of myArray (and will be releasing it in dealloc), it makes more sense to use the retain attribute. Otherwise, in order to avoid leaks, you'll require other objects to release the contents of myArray prior to calling your object's setter, since your assign setter won't do it for you.
You definitely can.
Using "assign" properties instead of "retain" properties is actually a common practice (see some core object header files from Apple for examples). The issue here is your code being aware of this memory relationship (if the property has something in it at any given time).
Some programmers prefer this pattern, in fact. Complete personal control of memory.
I would add, however, that it is a very difficult pattern to protect when there are multiple developers on a project unless they are all the types that like manually managing memory. It's much easier to leak memory in this pattern from a simple oversight and compilers have a tougher time interrogating such problems.
There is no reason why you can't do that. You just have to pay some extra attention to your memory.
Because what happens when you later assign to the property again?
Using your example:
#property (nonatomic, assign) NSArray *myArray;
#synthesize myArray;
...
self.myArray = [[NSArray alloc] initWithObjects: #"foo", nil];
self.myArray = [[NSArray alloc] initWithObjects: #"bar", nil]; // MEMORY LEAK!
In this case you would have to manually release your ivar by calling release on it. If you do not, you will have leaked the memory.
Another smart thing about having it retained (or copied, less bug prone) it that you can say:
self.myArray = nil;
This will release the variable AND set the reference to nil, so you avoid getting yourself into trouble.
I absolutely see your point though. It is alot more verbose to have to write 3 lines instead of one. You can as #willcodejavaforfood suggests use autorelease when you are assigning to retained properties, as he seems to have missed). But Apple suggests that on the iPhone you do as little autoreleasing as you can, and we always listen to apple like good little children.
Update:
When you specify a property as (nonatomic, assign) an synthesize it the setter code that is generated looks something like this:
- (void)setMyArray:(NSArray *)newValue {
myArray = newValue;
}
If you on the other hand define it as (nonatomic, retain) you get:
- (void)setMyArray:(NSArray *)newValue {
if (myArray != newValue) {
[myArray release];
myArray = [newValue retain];
}
}
Hope it clears things up.

Is it okay for multiple objects to retain the same object in Objective-C/Cocoa?

Say I have a tableview class that lists 100 Foo objects. It has:
#property (nonatomic, retain) NSMutableArray* fooList;
and I fill it up with Foos like:
self.fooList = [NSMutableArray array];
while (something) {
Foo* foo = [[Foo alloc] init];
[fooList addObject:foo];
[foo release];
}
First question: because the NSMutableArray is marked as retain, that means all the objects inside it are retained too? Am I correctly adding the foo and releasing the local copy after it's been added to the array? Or am I missing a retain call?
Then if the user selects one specific row in the table and I want to display a detail Foo view I call:
FooView* localView = [[FooView alloc] initWithFoo:[self.fooList objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:localView animated:YES];
[localView release];
Now the FooView class has:
#property (nonatomic, retain) Foo* theFoo;
so now BOTH the array is holding on to that Foo as well as the FooView. But that seems okay right? When the user hits the back button dealloc will be called on FooView and [theFoo release] will be called. Then another back button is hit and dealloc is called on the tableview class and [fooList release] is called.
You might argue that the FooView class should have:
#property (nonatomic, assign) Foo* theFoo;
vs. retain. But sometimes the FooView class is called with a Foo that's not also in an array. So I wanted to make sure it was okay to have two objects holding on to the same other object.
To answer your main question, yes you can multiple objects retaining an instance. That is exactly the point of reference-counted memory management. Have a look at the Cocoa Memory Management Programming Guide for more info. Then re-read it. It has all of the answers and will be your best friend.
Basically, sending a -retain message indicates that the sender "owns" the receiver in the sense that the receiver should not be deallocated until all owners have released their ownership. Thus, individual instances don't need to know (nor should they care) whether other owners exist. Retain anything you need to keep around and release it when you're done with it. When all owners have released their ownership, an intsance can be deallocated.
On a side note,
#property (retain,readwrite) NSMutableArray *myArray;
declares that the class declaring this property will retain the NSMutableArray instance. NSArray, NSDictionary, and NSSet (and their mutable subclasses) always retain their contents.
As others say, what you are doing is correct, and the code looks correct to me. I have tens of references to the same object in my code and as long as I have balanced all the retains and releases, everything works fine.
To add a bit more detail... you ask:
because the NSMutableArray is marked as retain, that means all the objects inside it are retained too?
These are two different things. All collection classes (Dictionaries, Arrays, Sets) automatically retain things that you add to them, and release their content objects when the collection object is deallocated. (In case of NSMutableArray, the content object gets released either if you remove it individually from array, or when you deallocate the whole array.)
This has nothing to do with whether the collection object itself is retained or assigned as a property. The only thing to consider there is that if your policy for the collection object property is not correct, it might get released sooner or later than you think and things may get out of balance.
As others say... read the memory management guide, and practice. :) Oh, and read other people's code too from this perspective and try to understand how/why they are doing their memory management.
One other small thing... for every retained property, make sure you have a release call in the object's dealloc method.
Yes, it's ok. That's the entire point of a reference counting memory management system.