Scenario1:
NSDictionary *dictionary =
[[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.stateZips = dictionary;
[dictionary release];
Scenario2:
self.stateZips = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
dependes on stateZips property.
If it is retained:
Scenario 1: stateZips is properly retained ( a release on stateZips will call its dealloc). also local dictionary is released then and there.
Scenario 2: stateZips is retained twice ( a release in stateZips will not call its dealloc as it is still retained).
If it is assigned:
Scenario 1: stateZips points to released dictionary and accessing it else where might result in crash.
Scenario 2: stateZips is properly retained ( a release on stateZips will call its dealloc).
copy is not being considered, as i believe its not your intention (at least in this piece of code)
Both cause self.stateZips to be set to a dictionary initialized with the file pointed to in plistPath.
But in the second, the pointer to the initialized dictionary was not saved, and as it's an object with a retain count of +1 technically a release message needs to be sent to it in some place, to balance the memory management. But as there is no way to retrieve the pointer to that object, you'll end up with a memory leak.
Two exceptions apply:
1.Garbage Collection
If you're in a garbage collected environment, both are the same. Well, they are not the same, but the result is similar.
2.Property type
If the setter for stateZips simply assigns the pointer, then you can release the object using the ivar pointer. Then these two pieces of code have only one difference: in the former, the object is released right after it's used. In the latter, it's just "undefined". Without the context, it's hard to determine if this object was released or not, and when.
I am assuming that stateZips is a property with the retain attribute.
In Scenario 1. A dictionary is created with a retain count of 1 in the first line. In the second line the property will call retain again, increasing the retain count to 2. Finally the retain count is decremented by the release. This will leave the dictionary with the correct retain count.
In Scenario 2, the retain is only called once.
The net effect of the two scenarios is the same. The dictionary object will be retained, and you will need to include a release in the dealloc method of the class.
If this were not correctly handled by the compiler, it would be very hard indeed following the retain/release rules of objective-c.
Related
In one interview i was asked to implement NSArray's exchangeObjectAtIndex:withObjectAtIndex: method.
I wrote the following code:
- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 {
id tmp = [self objectAtIndex:index1];
[self replaceObjectAtIndex:index1 withObject:[self objectAtIndex:index2]];
[self replaceObjectAtIndex:index2 withObject:tmp];
}
Interviewer said here's a memory management problem in first line and I'm going to catch bad_access_exc.
He recommended to write as this:
- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 {
id tmp = [[[self objectAtIndex:index1] retain] autorelease];
[self replaceObjectAtIndex:index1 withObject:[self objectAtIndex:index2]];
[self replaceObjectAtIndex:index2 withObject:tmp];
}
I understand that his code is right, but since tmp is local variable and it's going to be assigned, so there's no releasing and everything is gonna be ok. Is there any error?
If you are using manual memory management, there is an error. Apple has documented the problem under “Avoid Causing Deallocation of Objects You’re Using” in the Advanced Memory Management Programming Guide.
Specifically, objectAtIndex: doesn't retain and autorelease the object that it returns to you. So the NSArray might have the only “owning” reference to the object. Assigning to tmp under manual retain counting (MRC) doesn't retain the object so tmp doesn't own it and the autorelease pool doesn't own it.
This means that when line 2 of your method sends [self replaceObjectAtIndex:index1 withObject:[self objectAtIndex:index2]], the array might release the last reference to the object, deallocating it. At that point, tmp refers to a deallocated object; this is called a “dangling reference”.
Then in line 3, you try to put the dangling reference in the array. The array will send retain to the reference, which is invalid, and you will crash or experience heap corruption.
Under ARC, assigning to tmp does retain the object, so there is no error in that case.
Remember that id tmp is nothing more than a pointer to the object in your array. It doesn't say anything about the memory management of the object it's pointing to.
...it's going to be assigned, so there's no releasing...
This is the sticking point here. You can't guarantee that the object at index1 won't be deallocated when you replace it with the object at index2. In fact, the array will call release on it at this point to balance out the retain it called on the object when it was originally added to the array. Thus, it's possible that when the object at index1 is replaced will the object at index2, the reference count of the object at index1 will go to zero, the object will be deallocated, and your tmp variable will turn into a dangling pointer. The ... retain] autorelease] dance keeps the object around long enough to do the swap without having to worry about it deallocating before the end of the method (likely it will stick around until the top of the next run loop).
I think I have a pretty good understanding of ARC and the proper use cases for selecting an appropriate lifetime qualifiers (__strong, __weak, __unsafe_unretained, and __autoreleasing). However, in my testing, I've found one example that doesn't make sense to me.
As I understand it, both __weak and __unsafe_unretained do not add a retain count. Therefore, if there are no other __strong pointers to the object, it is instantly deallocated (with immutable strings being an exception to this rule). The only difference in this process is that __weak pointers are set to nil, and __unsafe_unretained pointers are left alone.
If I create a __weak pointer to a simple, custom object (composed of one NSString property), I see the expected (null) value when trying to access a property:
Test * __weak myTest = [[Test alloc] init];
myTest.myVal = #"Hi!";
NSLog(#"Value: %#", myTest.myVal); // Prints Value: (null)
Similarly, I would expect the __unsafe_unretained lifetime qualifier to cause a crash, due to the resulting dangling pointer. However, it doesn't. In this next test, I see the actual value:
Test * __unsafe_unretained myTest = [[Test alloc] init];
myTest.myVal = #"Hi!";
NSLog(#"Value: %#", myTest.myVal); // Prints Value: Hi!
Why doesn't the __unsafe_unretained object become deallocated?
[EDIT]: The object is being deallocated... if I try to substitute lines 2 - 3 with NSLog(#"%#", myTest); the app crashes (and an overridden dealloc in Test is being called immediately after the first line). I know that immutable strings will continue to be available even with __unsafe_unretained, and that a direct pointer to the NSString would work. I am just surprised that I could set a property on a deallocated object (line 2), and that it could later be dereferenced from a pointer to the deallocated object it belonged to (line 3)! If anyone could explain that, it would definitely answer my question.
I am just surprised that I could set a property on a deallocated object (line 2), and that it could later be dereferenced from a pointer to the deallocated object it belonged to (line 3)! If anyone could explain that, it would definitely answer my question.
When the object is deallocated it is not zeroed. As you have a pointer to the deallocated object and the property value is stored at some offset to that pointer it is possible that storing and retrieving that property value will succeed after deallocation, it is also quite possible that everything will blow up for some reason or other.
That your code works is quite fragile, try debugging it with "Show Disassembly While Debugging" and stepping through, you'll probably hit an access violation, or take down Xcode itself...
You should never be surprised that strange things happen in C, Objective-C, C++ or any of the family; instead reserve your surprise for so few strange things happening!
Because the constant string in objc is a constant pointer to a heap address and the address is still valid.
edited after comment:
Maybe because the memory at the test objects address hasn't been overwritten and still contains that object? Speculating....
You can see when Test is deallocated by implementing its -dealloc method and adding some simple logging.
However, even if Test is deallocated immediately, the memory it occupied in RAM may remain unchanged at the time you call myVal.
#"hi!" produces a static global constant string instance that is, effectively, a singleton. Thus, it'll never be deallocated because it wasn't really allocated in the first place (at least, it really isn't a normal heap allocation).
Anytime you want to explore object lifespan issues, always use a subclass of NSObject both to guarantee behavior and to make it easy to drop in logging hooks by overriding behavior.
Nothing strange there…
You need to have at least 1 strong reference to object to keep it alive.
Test * anTest = [[Test alloc] init];
Test * __weak myTest = anTest;
myTest.myVal = #"Hi!";
NSLog(#"Value: %#", myTest.myVal); // Prints Value: (Hi)
I am having problem with understanding one concept of memory managment, because I am new to objective C. For instance lets say I have a class Bar and Foo.
in main function I call:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo retain];
[foo callMethod];
[foo release];
I know this is right way to do it. But why do we have to retain it after we get it from another object, does not this mean returning object has retain count 0 ? so we have to reatin it to count 1 to use it? but if it has reatin count 0, how do we know it is still there. We can assume since it is the next line that increment retain count that the object memory wont be realocated, but what if we have multi-threading program?
When an class method returns an object, it will autorelease it so you don't have to bother; typically:
- (Foo *)getFoo
{
return [[_foo retain] autorelease];
}
If you are only using foo for the lifetime of the calling method you don't need to retain it, as it won't be autoreleased until next time through the run loop, so your code should actually be:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo callMethod];
If, however, you want to hold foo for a while, outside the scope of the calling method, you need to retain it and then release it sometime later.
One more thing; the convention for getter method names is simply "name", so your setter should be setFoo and your getter would be foo. Keeping to the naming conventions is a good idea as it lets you know what a method does, in say 7 months time, and tools like static analysis understand the conventions.
The method getFoo doesn't return an object with a 0 retain count. It returns an object with a +0 retain count which means that:
the object's retain count is not null (otherwise, the object wouldn't exist)
and the retain count wasn't altered by the invocation of the method, or if it was, it was in a balanced way (with as many release/autorelease as retain/alloc/new/copy).
Thus the lifetime of the object entirely depends on where and how it is retained. We don't know how long the object will be valid as any method invocation could release the object.
For example, let's consider the following code:
id anObject = [anArray objectAtIndex:0];
[anArray removeObjectAtIndex:0];
The object anObject isn't retained any more by the array as we removed it. Therefore it may have been destructed (but maybe it wasn't because it is still used somewhere else).
Generally, when getting an object from a method (other that alloc, copy, new or retain), we can assume that:
either the object was retained then autoreleased,
either the object is retained by the object that returned it.
So we know the object foo is valid until we return from the current method/function or we invoke a method/function that alter the state of the object bar, whichever comes first. After that, it may have been destructed.
So in your case, you can safely omit the retain/release pair.
However, it is very difficult to guaranty that an object doesn't get released unless we know the implementation of every method we invoke. Therefore, retaining (then releasing) every single object we get is the safer approach and that's what the compiler will do when you enable ARC (Automatic Reference Counting).
But that would require you to write a lot of retain/release and your code would become difficult to read, understand and maintain. Moreover, the more code you write, the more bugs you get (unless you never write bugs).
In conclusion, you don't need to retain an object unless you have a reason to suspect it could vanish otherwise.
NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.
How exactly does the addObject method of NSMutableArray work? Does it create a new instance and add it into the array or does it simply add a reference to the SAME object into the array?
If the answer is it only insert a reference to the object, then it leads to my next question:
Let's say I have the following method in one of my class ('list' is a NSMutableArray), gladly, this code works the way I wanted, but i just don't seem to fully understand why:
-(void)buyItem:(Item *)anItem
{
Item * newItem = [[Item alloc]init];
newItem.name = anItem.name;
newItem.details = anItem.details;
[list addObject:newItem];
[newItem release];
}
So basically after calling [list addObject:newItem], there would now be total of two reference pointing to the same object right(newItem, and another one in the 'list' array)?
But why does releasing the newItem object here, doesn't wipe out the one in the 'list' NSMutableArray? Aren't they pointing to the same Object?
When you are adding object to NSMutableArray using method addObject: it retains added object. This is why you can release it later and use afterwards by accessing using objectAtIndex: method.
It adds a reference and then increases the objects retain count by one. What you are doing is correct and it will still exist in the array with a retain count of one.
For your reference.
What increases an object's retain count?
It's important to understand the distinction between release and dealloc. release simply decrements the "retain count", except that when the count is decremented to zero, release goes on to dealloc the object.
In general (except where documented otherwise), when you pass an object reference (ie, pointer) to an Objective-C object, and it keeps a copy of that reference beyond the duration of your call to it, it retains the object on its own behalf, and it takes the responsibility to release the object when it is itself deallocated, or when the copy of the reference is nullified or overwritten.