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

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.

Related

Impact of releasing a variable more then the retain count

I have a instance variable declared as a retain property & then I released it 2 times. After releasing it I am not using it. This is not resulting into any crash. Is there any other impact of releasing a variable more than required (given that the variable is not going to be used after the release):
#property (nonatomic, retain) NSString *myVariable;
self.myVariable = nil;
self.myVariable = nil;
You are not, in fact, releasing it twice. This is because you're using properties. The first time you call self.myVariable = nil, you're releasing it (assuming it had a value). But the second time, it's already nil, so there's nothing to release.
In general, actually releasing an object multiple times (or more accurately, having more releases than retains) is really bad and will almost certainly crash your app.
You're not actually releasing it twice. Given that the setter looks something like this:
- (void)setMyVariable:(NSString)value
{
[myVariable release];
myVariable = [value retain];
}
The first self.myVariable = nil will release the myVariable iVar, and will also set it to nil. The next self.myVariable = nil will do nothing, because [nil release] does nothing.
Actually overreleasing an object will (usually) cause a crash.
You might be confused about the difference between a variable and an object. A single variable can be used with a release an infinite number of times (say, if is nil, or it holds a completely different retained object before each release, etc. This is because a variable can hold no object, or different objects at different times.). In your example, the variable holds no object (nil) during your second release.
But releasing any one non-nil object just one time too many can be the cause of a crash.
With the new ARC (Automatic Reference Counting) in iOS 5 you shouldn't worry about this issue, since the compiler takes care of this.
Learn more about it here:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html
However, if you can't / don't want to use ARC, here is my alternative answer:
By accessing your vars the way you are doing ( self.var = nil ), my guess is that these synthesized functions take care of not releasing a non-retained var, so you are safe to do so as many times you like (not very elegant though).
If, on the other hand, you would explicitly call release like this [var release] twice or more, you might run into pretty nasty problems.
Nothing will happen in your code. I assume you are using ARC (Automatic Reference Counting) so you are "releasing" it by setting its pointer to nil.
How it really works is, suppose you have a NSString object allocated in memory, you create it and you assign a pointer to it.
So now your pointer is pointing to that object, what arc does is: If an object no longer has a pointer pointing to it then it is automatically released. Assuming you had ONLY that "myvariable" pointer on that NSString then it will be released the moment you set it to nil.
If you set the myvariable to nil again then you are absolutely not doing anything to it since the object was already released before.
Note that this means that if you have ANOTHER variable also pointing to that NSString then the object WONT be released but myvariable wont be pointing to it anymore.
I forgot to mention, you can find an excellent explanation about how arc works in "iOS 5 by tutorials" by Ray Wenderlich.
PD: If you are using ARC u should change your
#property (nonatomic, retain) NSString *myVariable;
to
#property (nonatomic, strong) NSString *myVariable;

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

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.

get the value of a NSString variable

I have a weird problem.
pictureLink is a global variable declared in .h
NSString *pictureLink;
}
#property(retain,nonatomic) NSString *pictureLink;
i wrote this code
NSString * myPictureUrl=[NSString stringWithFormat:#"http://mywebsite.com/uploads/%#.jpg",hash];
pictureLink=myPictureUrl;
I have a strange result, it must be a pointer
Or
pictureLink=[NSString stringWithFormat:#"http://mywebsite.com/uploads/%#.jpg",hash];
i have EXC_BAD_ACESS error
It's memory management fault, you're not retaining myPictureUrl in your code.
[NSString stringWithFormat:#"http://mywebsite.com/uploads/%#.jpg",hash]; returns an autoreleased value, so you have two options:
pictureLink=myPictureUrl; should look like [self setPictureLink:myPictureUrl];.
do a [myPictureUrl retain];, and don't forget to release it later.
Consider using ARC (Automatic Retain Counting) for you project. With ARC the compiler takes care of retain counts so you don't have to, in fact aren't allowed to. There is a refactoring that will convert a current project.
You are bypassing your #property by calling directly the variable, so no magic provided by your #property settings is done, like retain and release.
you need to do self.pictureLink to use the #property.
To avoid the temptation of accessing directly my variable I do the following
NSString *theProperty
}
#property (nonatomic, retain) NSString *property;
and
#synthesise property = theProperty;
That way if I go around the #property I really, really wanted to do it.
But you need a very, very, very good reason to do so, and event then, it may not be a good enough reason.

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.