I'm having the code as below.
- (void)viewDidLoad
{
NSArray* myarr = [self createArray];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
[myarr release];
}
-(NSArray*)createArray
{
NSArray* arr1 = [[NSArray alloc] initWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
return arr1;
}
When I "Build & Analyze", its showing two leaks. One at [myarr release] saying, incorrect decrement of the reference count of an object that is owned at this point. and Other at return arr1, saying, Potential leak of an object allocated on line 152 and stored into arr1.
From my above code, the method "createArray" is returning a pointer and I'm releasing it as well. Is my way of coding right or wrong?
From my above code, the method "createArray" is returning a pointer and I'm releasing it as well. Is my way of coding right or wrong?
that depends on how you look at it.
1) the ref counting looks ok
2) the static analyzer flags objc methods based on names, in some cases. so the issue will likely vanish if you rename createArray to newArray, or something named new*. so it expects a convention (the ones used by Apple) to be followed.
therefore, it's the message that's bit shallow, it doesn't really analyze the program, but bases its findings/results on convention -- and not an actual evident issue which a human can read.
If you're just using the array in your viewDidLoad method, then you don't need to alloc an array in there at all. You can just use an autoreleased array returned as 7KV7 suggested. You can return an autoreleased array in your -(void)createArray as well without alloc'ing an object. Here is an example.
- (void)viewDidLoad
{
NSArray* myarr = [self createArray];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
}
-(NSArray*)createArray
{
return [NSArray arrayWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
}
If you don't have to alloc an object to use it, it makes for less, and cleaner code, IMO.
Try this
- (void)viewDidLoad
{
NSArray* myarr = [[NSArray alloc] initWithArray:[self createArray]];
for (NSString* str in myarr)
{
NSLog(#"%#",str);
}
[myarr release];
}
-(NSArray*)createArray
{
NSArray* arr1 = [[NSArray alloc] initWithObjects:#"APPLE",#"MAC",#"IPHONE",nil];
return [arr1 auotrelease];
}
The problem with your code is that
You do not allocate myarr using alloc or new so you do not take ownership of the object. Hence the issue in release.
You allocate arr1 so you take ownership of the object and you return arr1. Hence you do not release it. That is the reason for the leak.
Related
How to write right in this situation:
I have some method, that return NSMutableArray*. Because method not started with init, new or alloc, how write in apple memory-management guide, i return autorealese object.
-(NSMutableArray*)someMethod {
NSMutableArray *array = [NSMutableArray alloc] init] autorealese];
//Some code here
return array;
}
And i have some another methods, that call this one:
-(NSMutableArray*)method1 {
NSMutableArray *array = nil;
if(condition){
array = [self someMethod];
}
return array;
}
-(NSMutableArray*)method2 {
NSMutableArray *array = nil;
array = [self method1];
}
Code work.But XCode analyze tool says that in method2 i get object with count 0. So, how to write this code good?
There is nothing wrong with your code, except that the method2 will return the array that is autoreleased. Thus whatever is calling this method should retain the return value.
Creating an autoreleased NSMutableArray and returning it.
-(NSMutableArray*)someMethod {
NSMutableArray *array = [NSMutableArray alloc] init] autorealese];
//Some code here
return array;
}
Method1 uses autorelease NSMutableArray from someMethod and for the life of Method1 the array will not be autoreleased. That's one of the rules of memory management in objective-c that object lives through the method cycle.
-(NSMutableArray*)method1 {
NSMutableArray *array = nil;
if(condition){
array = [self someMethod];
}
return array;
}
Method2 uses still waiting to be autoreleased NSMutableArray from method1. It's important to notice that b/c you have a condition in method2 the array might be nil.
-(NSMutableArray*)method2 {
NSMutableArray *array = nil;
array = [self method1];
}
So in another words, you are passing autoreleased object along your methods. There is nothing wrong with this. You just have to remember that if you want to store the value of method2 you need to retain it, or it will get autoreleased.
Because of your condition in method1 the analyzer will complain b/c it's not guaranteed that the method1 will return an object, there is a possibility it will return nil.
I was running Leaks tool and discovered a massive leak in my Dictionary mutableDeepCopy but I can't figure out what's wrong with the code. Any suggestions?
#interface RootViewController : UIViewController{
NSDictionary *immutableDictionary;
NSMutableDictionary *mutableDictionary;
}
Here is the line of code that's highlighted in Instruments
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
Here is the method for creating a mutable copy of a Dictionary
#interface NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy;
#end
Here is method implementation, I've highlighted the code that Leaks saids is leaking 100%
- (NSMutableDictionary *) mutableDeepCopy {
NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for(id key in keys) {
id value = [self valueForKey:key];
id copy = nil;
if ([value respondsToSelector:#selector(mutableDeepCopy)]) {
copy = [value mutableDeepCopy];
} else if ([value respondsToSelector:#selector(mutableCopy)]) {
copy = [value mutableCopy]; //This is the Leak
}
if (copy == nil) {
copy = [value copy];
}
[dictionaryToReturn setValue:copy forKey:key];
}
return dictionaryToReturn;
}
You need to analyse this in light of Apple's Memory Management Rules.
Starting with this line:
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
I would expect mutableDeepCopy to return an object I own, so at some point I need to release or autorelease it. e.g.
NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy];
self.mutableDictionary = temp;
[temp release];
or
self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease];
So now we need to look at mutableDeepCopy. Because it has 'copy' in the name it needs to returned an "owned" object which, in practice means "forgetting" to release the returned object. You have already failed to do that when you create the returned object in the first line, since dictionaryWithCapacity: gives you an object you do not own. Replace it with
NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
Now you own it.
It is important that you make your mutableDeepCopy obey the rules because it means you can treat the objects returned from mutableDeepCopy, mutableCopy and copy in exactly the same way. In all three cases you own the object copy that you insert into the array. Because you own it, you must release it or it'll leak as you found out. So, at the end of the loop, you need
[copy release];
That'll stop the leak.
How is your property declared? If is is retain or copy, then this doesn't leak.
Your problem is that the name mutableDeepCopy suggests that it returns a retained object, and not an autoreleased one as it actually does.
Edit:
And at the mutableDeepCopy itself, you need to release the copy variable after adding to the dictionary.
mutableCopy increments the retain count of the object, as does setValue:forKey:. This means that when dictionaryToReturn is dealloc'ed, the object that had mutableCopy called still has a retain count of one.
Try doing this instead:
copy = [[value mutableCopy] autorelease];
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.
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]];
I'm using the following method in my code:
- (NSMutableArray *) newOrderedArray:(NSMutableArray *)array ByKey:(NSString *)key ascending:(BOOL)ascending {
NSSortDescriptor *idDescriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending];
NSArray *sortDescriptors = [NSArray arrayWithObject:idDescriptor];
NSArray *orderArray = [array sortedArrayUsingDescriptors:sortDescriptors];
[idDescriptor release];
NSMutableArray *result = [NSMutableArray arrayWithArray:orderArray];
return result;
}
Is this a well-coded convenience method? As I think, it returns an autoreleased NSMutableArray.
This method is called by another one:
- (id) otherMethod {
NSMutableArray *otherResult = [[[NSMutableArray alloc] initWithCapacity:[otherArray count]] autorelease];
// I add some stuff to otherResult and then...
NSMutableArray *result = [dbUtils newOrderedArray:otherResult ByKey:#"objectId" ascending:NO];
return result;
}
This method (otherMethod) is called in some view controller where I want to store returned array and release it when deallocating the view controller. However, when [result retain] is called in this view controller (because I need it to be available and I can't allow it to be deallocated) I receive the following error:
[CFArray release]: message sent to deallocated instance
I've tried to log [result retainCount] just before calling retain and it print "1". I don't understand why an error is thrown when calling retain.
Thank you,
A
I don't see anything technically wrong with the code above--otherMethod should return an autoreleased NSMutableArray. Are you sure you're getting the error when calling retain? It looks more like you might be accidentally be sending release at some point instead of retain.
Stylistically, there's one thing--methods with "new" in the title should always return non-autoreleased objects, so you should either name your method something else (such as orderedArray...) or use [[NSMutableArray alloc] initWithArray:] instead of arrayWithArray. Also, method signatures shouldn't start with a capital (so ByKey should be byKey.
try this:
NSMutableArray *otherResult = [[NSMutableArray initWithCapacity:[otherArray count]];
Because initWithCapacity will return an autoreleased Array. Right now you tell the Autoreleasepool to release the Array twice.
initWithCapacity:does not return an autoreleased object. – Wevah
AFAIK initWithCapacity is a convenience initializier, which by convention return autoreleased objects. So if the object is only used within a local method, the autoreleasepool should deallocate it. Care to elaborate?