Printing element removed from nsarray - objective-c

I am playing with objective-c and did sample test.
In non-arc environment I have the following code:
NSNumber * one;
NSLog(#"At first one retain count is: %d",[one retainCount]);
one = [[NSNumber alloc]initWithInt:5];
NSNumber * two = [[NSNumber alloc]initWithInt:1];
NSNumber * three =[[NSNumber alloc]initWithInt:2];
NSLog(#"After initializing %d",[one retainCount]);
NSMutableArray * array = [NSMutableArray arrayWithObjects:one,two,three, nil];
NSLog(#"After adding to array it is: %d",[one retainCount]);
NSString * a = [array objectAtIndex:0];
NSLog(#"Assigning to variable a: %d",[one retainCount]);
NSLog(#" %# ",a);
[one release];
[array removeObjectAtIndex:0];
NSLog(#"after releasing and removing from array %d",[one retainCount]);
NSLog(#" %# ",a);
It seems like the I wouldn't be able to use nslog the variable a but I can do it.
I am getting the following output;
2013-03-07 17:57:09.706 Interview[33491:11303] At first one retain count is: 3
2013-03-07 17:57:09.707 Interview[33491:11303] After initializing 2
2013-03-07 17:57:09.707 Interview[33491:11303] After adding to array it is: 3
2013-03-07 17:57:09.707 Interview[33491:11303] Assigning to variable a: 3
2013-03-07 17:57:09.707 Interview[33491:11303] 5
2013-03-07 17:57:09.707 Interview[33491:11303] after releasing and removing from array 1
2013-03-07 17:57:09.708 Interview[33491:11303] 5
How it's possible that I can still use the variable a even if I it supposed be deallacated?

You'll get told many times you should not use retainCount, but your question is:
How it's possible that I can still use the variable a even if I it supposed be deallacated?
When an object is deallocated that simply means that the memory that was used for it is added to the pool of available memory. The memory previously in use is not completely overwritten to remove all traces of what was stored in it.
Furthermore when you invoke [one release] this only indicates you no longer have an interest in the object referenced by the value stored in one (and as a result that object's memory may be returned to the free pool) it does not alter the value stored in one itself. So after the call one still contains the reference to where the object was, or still is...
If you wish to make sure you don't use an out-of-date reference you can use code like:
[one release]; one = nil;
Finally you report that before you even allocate your object your first NSLog outputs:
2013-03-07 17:57:09.706 Interview[33491:11303] At first one retain count is: 3
How can you have a retain count of 3 when you've never even allocated an object? The answer is you are lucky your code didn't blow up; when a local variable, which your one appears to be, is created it starts with garbage contents - calling a method using that garbage as an object reference is unwise. Remember Objective-C is not a "safe" language and will not protect you from such errors. Note that instance and global variables are initialised to 0/nil, and invoking methods on nil is supported in Objective-C - you just get 0 back.

Because you can never be fully sure that your object hasn't been retained elsewhere in the framework. Be sure you obey the memory management policy, and let the framework worry about its obligations.
Additionally, don't use retainCount. Apple tells you explicitly not to use it, and it isn't guaranteed to tell the truth.
Directly from the documentation: Do not use this method.
Special Considerations
This method is of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
To understand the fundamental rules of memory management that you must abide by, read “Memory Management Policy”. To diagnose memory management problems, use a suitable tool:
The Clang Static analyzer can typically find memory management problems even before you run your program.
The Object Alloc instrument in the Instruments application (see Instruments User Guide) can track object allocation and destruction.

Look here, this explains everything more clearly:
http://www.whentouseretaincount.com

Related

Memory management in local variable objective-c

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).

AXUIElementRef and ARC - Deallocated instances and __bridge vs __bridge_transfer

I get this error on an NSMutableArray:
-[Not A Type release]: message sent to deallocated instance 0x1006e29c0
It happens on this line:
[_array removeAllObjects];
Now, I understand what the error means but not why it happens in this case.
I've added an NSLog right before the above line like so:
NSLog(#"%#", [_array class]);
And this executes normally and with the correct behavior, this is the log:
2013-03-13 11:19:27.366 App[66921:303] __NSArrayM
2013-03-13 11:19:27.367 App[66921:303] *** -[Not A Type release]: message sent to deallocated instance 0x1006e29c0
So right before removing it doesn't seem to be deallocated..
Even if I remove the removeAllObjects call and replace it with the below line, I still get the same error.
_array = [[NSMutableArray alloc] init];
All I'm doing elsewhere in the code is calling [_array addObject:...]
_array is a strong property:
#property (strong) NSMutableArray *array;
The array is first initialized in the init method.
EDIT: I'm adding AXUIElementRefs to this array like so:
[_array addObject:(__bridge_transfer id)elementRef];
I thought the __bridge_transfer brings it over to ARC and I wouldn't need to manage any of that?
What could be the problem?
UPDATE:
Here is a sample project: http://users.telenet.be/prullen/AXMemory.zip
This is a working project as I'm using __bridge and not __bridge_transfer.
This project contains a simple loop that does the same thing over and over again. This is to demonstrate that with just __bridge, the AXUIElementRefs never get released. They stay in memory. That's what I see in the Instruments profiler too. You can also see the memory usage increasing every few seconds via activity monitor.
The AXUIElementRefs were obtained via AXUIElementCopyMultipleAttributeValues - so I would assume that I would have ownership of them? Nevertheless, changing to __bridge_transfer results in the errors above.
If anyone could take a look at this and let me know what I'm doing wrong, that would be much appreciated.
I get an array of properties via the following statement: (line 60).
AXUIElementCopyMultipleAttributeValues(frontWindowRef, attributes,0,&attributeValues);
Line 110 I assign the AXUIElement (looping over the children array):
element = CFArrayGetValueAtIndex(childrenArrayRef, i);
Line 112 is where I add the AXUIElementRef to the array:
[_array addObject:(__bridge id)(element)];
Line 36 is where I empty it if it's over 500 elements:
if ([_array count] > 500) {
[_array removeAllObjects];
}
You can't just assume that __bridge_transfer "brings it over to ARC and [you] wouldn't need to manage any of that". You have to understand what rights and responsibilities you had for elementRef at the time (which we can't tell from what you've written).
I find it's much easier to understand the bridge casts if you use the corresponding CFBridgingRetain() and CFBridgingRelease() functions. __bridge_transfer is the same as CFBridgingRelease(). So, the question is: do you own elementRef at the time? Is it appropriate for you to release it?
Consider, would the following have been correct?
[_array addObject:(__bridge id)elementRef];
CFRelease(elementRef);
If not, then neither is __bridge_transfer.
From the nature of the error you're getting, I strongly suspect you were not entitled to release elementRef, so you were not entitled to tell ARC that it owns it and must release it. You have caused the AXUIElementRef to be over-released. You should just have used a __bridge cast – no "transfer" and no CF…Release().

what's the difference between two code scenario

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.

Reference count is still 1 after [obj release], when it should be deallocated

When I create an object and check its retain count, I get 1 as expected. When I release the object and then check the retain count again, it is still 1. Shouldn't the object be deallocated, and the retain count 0?
NSMutableString *str=[[NSMutableString alloc] initWithString:#"hello"];
NSLog(#"reference count is %i",[str retainCount]);
[str release];
NSLog(#"reference count is %i",[str retainCount]);
I do see 0 for the retain count if I set str to nil first. Why is that?
Don't use retainCount, it doesn't do what you expect in most cases.
Your second NSLog is accessing deallocated memory as an object. In this particular case, that deallocated memory still contains enough of the old data from the NSString that was just freed for the program to not crash when the retainCount method is called on it. Had you run this with NSZombieEnabled you would have gotten an error message about sending a message to a deallocated instance.
The reason it returns 0 when called for nil is that methods returning integers will always return 0 when called on a nil object.
Do not depend on retainCount. And do not care about this. Lots of things may happen under the hood. You only need to ensure that you have released all the things that you owned. If you are trying to be sure that you are not leaking any memory, then use Instrument, not retainCount in NSLog.

Differences between NSStrings?

I understand that the v03 example creates an object that I own and must ultimately release. What I would like to know is are there any differences between the first two(v_01 & v02), or are they essentially the same?
// Version_01
userName = #"Teddy";
// Version_02
userName = [NSString stringWithString:#"Gary"];
// Version_03
userName = [[NSString alloc] initWithString:#"Caroline"];
... some code
[userName release];
gary
They are all similar, but there are some slight differences between the three.
The first one is a pointer to a string constant. The string Teddy is stored in read-only memory, and userName is a pointer to this string constant. You need not (and cannot) retain or release this object, since it exists "permanently" (that is, for the duration of the program).
The second one is an autoreleased string object with the contents Gary. When returned to you, it has a release count of 0. It may be retained and released as needed.
The third one is similar to the second one, but it is not autoreleased, so it has a retain count of 1 when it is initially returned to you. Like the second one, it may be retained and released as needed.
Most of the differences in these instances is how the memory is managed. If you want a clearer view of what's happening in the background, you might want to peruse the Objective-C Memory Management Guide.
// Version_01
userName = #"Teddy";
This is a String constant that does not have any memory management associated with it. The memory used to hold the value is part of the memory in which the code resides in (essentially). retain and release calls on the variable will be ignored.
// Version_02
userName = [NSString stringWithString:#"Gary"];
This is an autoreleased instance of an NSString object. Its retain count is currently one and will be released by the autorelease pool soon unless it is retained.
// Version_03
userName = [[NSString alloc] initWithString:#"Caroline"];
[userName release];
This is a managed instance of an NSString. When it is first initialized, its retain count is one. After releasing it, the retain count went down to zero, therefore, its memory will be deallocated. Referring to the variable userName after releasing it will cause an EXE_BAD_ACCESS error.
The first two or essentially the same
The latter one is not however as userName would be an invalid string object at that point.
However changing it to
userName = [[[NSString alloc] initWithString:#"Caroline"] autorelease];
would render it effectively the same as the previous two.
version 01: is a string constant....
version 02: is an auto-released NSString created by copying a constant.
Practically, there are no differences, as long as you don't attempt to use the Version_03 string after you release it. If you want to do that, you'll need to autorelease it instead.