NSDictionary release triggers the release of valueForKey

I am currently trying to work on iOS. I am currently having problems with memory management. This is the reason for my confusion:

NSString *path = [self.dataPath stringByAppendingPathComponent:@"dummy.plist"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
NSString *dummyKeyValue = [dict valueForKey:@"dummyKey"];

// NSLog(@"%@",[NSString stringWithString:dummyKeyValue]);

[dict release];

NSString *anotherString = [dummyKeyValue lowercaseString];

      

This piece of code raises the EXC_BAD_ACCESS error on the last line. It looks like because NSDictionary releases its key values. I don’t understand why the definition is dummyKeyValue

not counted because obviously dummyKeyValue

still points to the value "dummyKey"

.

Now the next problem, and even funnier thing, occurs when you comment out a line NSLog

. Using dummyKeyValue

in one way or another prevents the memory it points to from being released. Why?

Help is appreciated!

+3


source to share


4 answers


In manual reference counting mode, simply defining a variable does not mean that the object the variable points to will be automatically saved. When dict

freed, it frees its value objects, and if there are no other objects with a strong reference to them (i.e., their reference count is now 0), they are freed. This is what you see here.

If you want to keep a strong reference to dummyKeyValue, you need to keep it after getting it. Of course, this also means that you need to release him when you're done with him. Try the following:

NSString *dummyKeyValue = [[[dict valueForKey:@"dummyKey"] retain] autorelease];

      



Now dummyKeyValue will stick to the end of the current autocomplete pool range. Often times accessors are written to do this before returning a value to avoid the situation you see.

It should be noted that if you are using ARC (Automatic Reference Counting) you would not have this problem as the compiler inserted the necessary save / deallocation calls to ensure the dummyKeyValue is stuck until you are done with it.

+3


source


This is basic memory management. When you create dict

, a dictionary manages the memory of all the keys and values ​​it contains.

When you get a value and assign it to a variable dummyKeyValue

, you are not doing any additional memory management by value. You just have a variable pointing to an object.

Now when you release dict

, the dictionary also releases all of its keys and values. In other words, all keys and values ​​have a retention rate of one. Since there is nothing else left in the keys and values ​​at this point, they are all freed.

At this point, your variable has dummyKeyValue

pointed to the freed value, which is causing the crash.



You have the opportunity to fix this.

  • Save the value stored in dummyKeyValue

    (to be released).
  • Transfer the call [dict release]

    after last use dummyKeyValue

    .

The reason the operator NSLog

fixes the problem is because yours NSLog

creates autoreleased NSString

. This one NSString

retains the value you used to create it. So when dict

freed, NSString

it still has a reference to the same object as dummyKeyValue

. This allows this object to live a little longer, preventing a crash.

+2


source


(You must use objectForKey:

to extract items from NSDictionary

.)

Turn on ARC first. If you're just getting started with Cocoa, there are many other things you need to learn about the environment besides memory management. The vendor-linked compiler will take care of 99% of your memory management problems and you should allow it. This has always been a major stumbling block for new Cocoa developers and has now been eliminated. Come back to this topic later, once you understand the rest. For now, ignore the rest of this answer. There is no third step.

So here's what's going on here:

When you get an object from the dictionary using objectForKey:

, you don't get ownership of it. It's just a reference and the dictionary still owns the object. If you destroy a dictionary, all of its objects come with it - unless they are owned (stored) by something else. If you want the object to live after the dictionary is destroyed, you need to claim it with retain

:

NSString *dummyKeyValue = [[dict objectForKey:@"dummyKey"] retain];

      

By acquiring ownership in this way, you are also responsible for relinquishing that ownership, either by using release

when you are done with the object or auto-implementing it, in which case it will be released some time after this method ends.

Using the resulting object as an argument for stringWithString:

makes it live, because seemingly as an internal detail that cannot be relied on, this method stores and auto-implements the argument. Or something else that you cannot rely on. This is an interesting find, but not a practical method of managing an object's lifetime.

+2


source


You should write:

NSString *dummyKeyValue = [[dict valueForKey:@"dummyKey"] retain];

      

or

NSString *dummyKeyValue = [[dict valueForKey:@"dummyKey"] copy];

      

It doesn't matter that you have a link to objec as you are not using ARC. Each object has a reference count. Your counter dummyKeyValue

is 1 until your dictionary is found. When you release it, the number of references decreases (becomes 0) and the object is freed. Thus, it dummyKeyValue

points to nothing.

By the way, if you want to increase the number of object references, use retain

also release

to decrease it.

0


source







All Articles