About memory management in iPhone - iphone

Please clarify the following thing.
Everyone knows that; if we are using alloc, retain, new and etc..., we have to release it. For remaining things, we have to use autorelease. My doubt is;
-(NSArray*)getArray{
NSArray *array = [[NSArray alloc] initWithObjects:#"1", #"2", #"3", #"4", #"5", nil];
return [array autorelease];
}
NSArray *arr = [self getArray];
---
---
What we have to do the arr?
EDIT:
NSString *str = [NSString stringWithFormat:#"Welcome..."];
If we are using the above statement, we should call autorelease. But I want to know, what is happening in the stringWithFormat:method. How it is returning NSString.
Thanks.

If you are planning to return the array, go ahead and use the [NSArray arrayWithObjects:#"1", #"2", etc, nil] instead.
You then just need to remember to retain it if you want to hold on to it for longer then the autorelease pool will hold it.
The autorelease pool will give it a retain count of 1, and then automatically decrement it by 1 when the release pool gets called. Without retaining it in the calling function, this object will eventually disappear.

You don't have to do anything with arr since you didn't explicitly alloc, copy, new, or retain it in its current scope. It's already been added to the autorelease pool so it'll automatically be cleaned up once you're done with it.
EDIT: In your edited question, [NSString stringWithFormat:] returns an autoreleased string. It's basically doing the same thing as you're doing in your getArray method. It builds a NSString (or related) object and autoreleases it before it's returned.

You should retain:
[[self getArray] retain];
Or return non-autoreleased object in getArray.

Your getArray method is returning an NSArray that _will_be_ released when the stack fully unwinds.
In the method where you are calling your getArray method, it is safe to use the NSArray, but if you want to keep it, and use it after your current method returns, you will need to retain the NSArray with [arr retain].
Answer to your new question
Class methods, like [NSString stringWithFormat:] or like [NSURL URLWithString:] return objects that have been autoreleased. This is a convention, a standard practice in UIKit and the Apple frameworks.

Related

Will this Objective-C, nested NSArray cause a memory leak on iPhone?

NSArray *tLines = [[NSArray alloc] initWithObjects:
[[NSArray alloc] initWithObjects:#"Matt", #"David", nil],
[[NSArray alloc] initWithObjects:#"Bob", #"Ken", nil], nil];
self.lines = tLines;
[tLines release];
I'm allocing NSArrays within an NSArray, will the nested arrays get released when I call [lines release];?
Why don't you use a convenience method? No need to release memory.
NSArray *tLines = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:#"Matt", #"David", nil],
[NSArray arrayWithObjects:#"Bob", #"Ken", nil], nil];
Yes, this will cause a leak.
When created, the sub-arrays have a retain count of 2 (from alloc and adding to the array). When tLines is released, this is decremented to 1; which isn't enough to cause it to be deallocated; meaning that they leak.
Use +[NSArray arrayWithObjects] or autorelease the arrays on creation.
Remember: NARC (New, Alloc, Retain, Copy) should always be balanced with a release or autorelease.
No, you should not do this. When you alloc the arrays, you need to release them. The containing array will handle memory management for its objects (retaining them when they're added, releasing when they're removed), but that is beside the responsibility of the object that created to the arrays to properly release them. You should either use a convenience constructor to create the arrays or else create them one at a time and release them after they've been added to the master array.
I'm pretty sure it will leak, unless you release each object yourself before clearing the Array...
Or try using autorelease option at the creation, it'll do the work for you...

Should I release array returned from [NSMutableDictionary ValueForKey: ]

I have a NSMutableDictionary with the key being the first alphabet of the name of an object. The view is something like the 'Contacts' tab on iphone. Additionally user can select individual objects in the list.
In the code I find each selected object to process them further.
NSMutableArray *objectsToAdd = [[NSMutableArray alloc] init];
NSMutableArray *array = nil;
for (NSString *key in self.nameIndex) {
array = (NSMutableArray *)[searchedNameDictionary valueForKey:key];
for (Objects *eachObject in array) {
if (eachObject.objectIsSelected){
[objectsToAdd addObject:eachObject];
}
}
}
[array release];
-(void)dealloc()
{
[searchedNameDictionary release];
}
The app is crashing where I release searchedNameDictionary, with the message that the deallocated object is being referenced.
Now if in the code above, I remove [array release] the app works fine.
My question is does releasing 'array' is actually releasing the objects in searchedNameDictionary, which is what seems to be happening.
Would not releasing array cause memory leak?
You shouldn't release returned object unless they come from an alloc or copy method.
Returned objects are autoreleased otherwise, if you want to keep it around your should retain it right after receiving it.
array = (NSMutableArray *)[searchedNameDictionary valueForKey:key];
This returns an autoreleased object, thus you don't need to release it.
There are some other...issues with your code too, but mostly style things. Get rid of the [array release] and you're good to go as far as that issue is concerned.

Why Instruments report a leak?

I am developing an iphone app. Instruments reported a leaked object ServiceTypes. Below is the relevant code. Does anyone have any ideas? Thanks a lot for your help.
ServiceTypes *serviceTypes = [[ServiceTypes alloc] init];
if ([userConnection getServiceTypes:serviceTypes]) {
if ([serviceTypes.types length] > 0) {
NSArray *array = [[NSArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString: SERVICE_TYPE_DELIMITOR]];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:array];
[array release];
}
}
[[self typesTableView] reloadData];
[serviceTypes release];
It doesn't look like serviceTypes is being leaked. From the code you posted, serviceTypes is always released at the end of the method, and it doesn't appear to be retained anywhere in your sample. My question is: what happens inside getServiceTypes:. Does that method retain the serviceTypes parameter?
One more thing. If serviceRequestTypes is an instance variable (and it looks like it is), then you may be leaking memory by reassigning it without releasing the existing serviceRequestTypes object first. You should either rewrite serviceRequestTypes to be a property and use a synthesized accessor or make sure to release it every time before assigning. If its current value is nil, no big deal; the release message will simply be ignored. For example:
[serviceRequestTypes release];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString:SERVICE_TYPE_DELIMITER]];

should variable be released or not? iphone-sdk

In the following piece of code (from a book) data is an NSDictionary *data; defined in the header (no property).
In the viewDidLoad of the controller the following occurs:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *keys = [NSArray arrayWithObjects:#"home", #"work", nil];
NSArray *homeDVDs = [NSArray arrayWithObjects:#"Thomas the Builder", nil];
NSArray *workDVDs = [NSArray arrayWithObjects:#"Intro to Blender", nil];
NSArray *values = [NSArray arrayWithObjects:homeDVDs, workDVDs, nil];
data = [[NSDictionary alloc] initWithObjects:values forKeys:keys];
}
Since I am really new to objective-c can someone explain to me why I do not have to retain the variables keys,homeDVDs,workDVDs and values prior exiting the function? I would expect prior the data allocation something like:
[keys retain];
[homeDVDs retain];
[workDVDs retain];
[values retain];
or not? Does InitWithObjects copies (recursively) all objects into a new table?
Assuming we did not have the last line (data allocation) should we release all the NSArrays prior exiting the function (or we could safely assumed that all NSArrays will be autoreleased since there is no alloc for each one?)
Thanks!!!!
In Core Foundation, most of static calls to methods such as arrayWithObjects: return autoreleased instances, which means you don't need to (and even must not!) release it by yourself.
So the situation after your code is executed is that all arrays you created with arrayWithObjects: calls are autoreleased, but are retained when added to other array or dictionary. So homeDVDs and workDVDs are retained when added to the values array, and keys and values arrays are both retained when added to the data dictionary.
So you don't need to explicitly release your arrays, but you'll need to release your data dictionary at some point (perhaps in dealloc method implementation).
NSDictionary copies the key field and retains the values. All your other instances are autoreleased, so you're not missing any releases or retains (assuming you release data in the dealloc method).

Why am I having trouble with a deep copy in Objective C?

I'm assuming my understanding of how to perform a deep copy isn't just there yet. The same with some sub-optimal memory handling that I'm performing down below. This code below probably depicts a shallow copy, and I believe that's where my problem might be. I have some cookie-cutter code for an example that looks like the following:
NSArray *user = [[xmlParser createArrayWithDictionaries:dataAsXML
withXPath:kUserXPath] retain];
if([user count] > 0) {
self.name = [[user valueForKey:#"name"] copy];
}
// Crash happens if I leave the next line un-commented.
// But then we have a memory leak.
[user release];
[xmlParser release];
Unfortunately when I comment out [user release], the code works, but we have an obvious memory leak. The method createArrayWithDictionaries:withXPath: was refactored last night when the SO community helped me understand better memory management. Here's what it looks like:
- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument
withXPath:(NSString *)XPathStr {
NSError *theError = nil;
NSMutableArray *dictionaries = [NSMutableArray array];
CXMLDocument *theXMLDocument = [CXMLDocument alloc];
theXMLDocument = [theXMLDocument initWithXMLString:xmlDocument
options:0
error:&theError];
NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
for (CXMLElement *xmlElement in nodes) {
NSArray *attributes = [xmlElement attributes];
NSMutableDictionary *attributeDictionary;
attributeDictionary = [NSMutableDictionary dictionary];
for (CXMLNode *attribute in attributes) {
[attributeDictionary setObject:[attribute stringValue]
forKey:[attribute name]];
}
[dictionaries addObject:attributeDictionary];
}
[theXMLDocument release];
return dictionaries;
}
I'm guessing there's a couple of issues that might be going on here:
Auto release on my dictionaries array is happening, thus my app crashing.
I'm not performing a deep copy, only a shallow copy. Thus when the user array is released, self.name is done for.
With NSZombieEnabled, I see the following:
*** -[CFString respondsToSelector:]:
message sent to deallocated instance 0x1ae9a0
Also, the final call where the backtrace shows this is crashing contains the following code in a separate module from the other two methods:
User *u = self.user;
NSString *uri = [NSString stringWithFormat:#"%#/user/%#/%#",
[self groupName], u.userId, kLocationsUri];
Between all the auto releasing/copies/retain happening between the client code and createArrayWithDictionaries:withXPath, I'm a bit confused as to the real problem here. Thanks again for helping me understand.
OK, you don't need to retain the return value from createArrayWithDictionaries: since you're not keeping it around. The return value is autoreleased. I'd strongly recommend reading up on how autoreleasing works. You only retain things that you intend to keep around in your object.
Also, user is an NSArray. If you call [user valueForKey:#"name"], you'll get another NSArray of values representing the values of the name key for each of the objects in users. Furthermore, how is the name property on your object defined? If you declared it as copy or retain (I believe retain is the default if you don't specify it yourself), you don't need to copy or retain the value. Indeed, the accessor should always be responsible for doing the memory management, not the caller. If you wrote your own accessor (i.e. you didn't use the #synthesize keyword), you need to make sure you do the memory management there.
I'm guessing what you meant to write was something more like this:
NSArray *user = [xmlParser createArrayWithDictionaries:dataAsXML withXPath:kUserXPath];
if ([user count] > 0)
self.name = [[user objectAtIndex:0] objectForKey:#"name"];
[xmlParser release];
I think your troubles are stemming from a misunderstanding of how memory management works in Objective-C.
Hope this helps.
Auto release on my dictionaries array is happening, thus my app crashing.
If the caller intends to keep the array around somewhere, it needs to retain it. Otherwise, it will crash when it tries to access the (now-deceased) object.
If the caller is going to store it in a property, it must use the self.dictionaries = […] syntax, not dictionaries = […]. The former is a property access, which calls the setter method; the latter is a direct instance variable assignment.
Coming back to your actual question, that of a deep copy: You need to get the sub-elements of every element and put them in each element's dictionary.
Basically, you need a recursive method (or a queue, but that's harder—file under premature optimization until you've proven you need it) that takes an element and returns a dictionary, and then you need to call this method on each of your element's child elements, and collect the results into an array and put that into the dictionary you're creating.
I would recommend making this recursive method an instance method of the element. Something like:
- (NSDictionary *) dictionaryRepresentation {
NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
for (CXMLNode *attribute in attributes) {
[attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
}
NSArray *childElements = [self childElements];
return [NSDictionary dictionaryWithObjectsAndKeys:
attributeDictionary, #"attributes",
[childElements valueForKey:#"dictionaryRepresentation"], #"childElements",
nil];
}
Then you replace the loop in createArrayWithDictionaries:withXPath: with a similar valueForKey: message. I'll leave you to fill it in.
valueForKey: is Key-Value Coding's principal method. In both places, we're making use of NSArray's handy implementation of it.
(If the use of valueForKey: still doesn't make sense to you, you should read the KVC Programming Guide. KVC is vitally important in modern Cocoa, so you do need to read this sooner or later.)