NSMutableArray Leaks in Loop - iphone

I´m using instruments to find memory leaks, and it found a lots!
But i don´t know how to fix it.
#property(nonatomic, retain) NSMutableArray *wycategories;
...
...
self.wycategories = [[NSMutableArray alloc]init];
...
...
for (CXMLElement *node in nodes) {
//Instruments say that here there are a lots of memory leaks
WaiYahCategory *wycategory = [[WaiYahCategory alloc] init];
wycategory.text = [[node childAtIndex:0] stringValue];
wycategory.idCategory = [[node attributeForName:#"id"] stringValue];
wycategory.desc = [[node attributeForName:#"desc"] stringValue];
wycategory.icon = [[node attributeForName:#"icon"] stringValue];
[self.wycategories addObject:wycategory];
[wycategory release];
}

As the wycategories has a retain attribute, you have to release the array after the assignement.
NSMutableArray *array = [[NSMutableArray alloc]init];
self.wycategories = array; // <- The property retains the array
[array release];

Related

How to compare two MutableArrays and display the unmatched value in iphone? [duplicate]

This question already has answers here:
Compare 2 nsmutablearray and get different object to third array in ios
(4 answers)
Closed 9 years ago.
I have two MutableArray values like.
NSMutableArray *array=[[NSMutableArray alloc]initWithObjects:#"Apple", #"Orange", #"Grapes", #"Banana", nil];
NSMutableArray *array1=[[NSMutableArray alloc]initWithObjects:#"Apple", #"Orange", #"Grapes", nil];
Now i have to compare that two Mutable arrays and display that unmatched object "Banana" into one string.
I am fresher to iOS so, anybody would send me the code for that problem.
Thanks in Advance.
As others have suggest, NSSet is probably your best bet. However, given that *array is mutable, you could simply remove the objects from it contained in *array1
NSMutableArray *array=[[NSMutableArray alloc]initWithObjects:#"Apple", #"Orange", #"Grapes", #"Banana", nil];
NSMutableArray *array1=[[NSMutableArray alloc]initWithObjects:#"Apple", #"Orange", #"Grapes", nil];
[array removeObjectsInArray:array1];
NSLog(#"array: %#", array); // array: ( Banana )
// if you require result as a string
NSString *objectsAsString = [array componentsJoinedByString:#", "];
NSLog(#"objects as string: %#", objectsAsString); // objects as string: Banana
for(int i=0;i<[array count];i++)
{
NSString *str1 = [array objectAtIndex:i];
for(int j=0;j<[array1 count];j++)
{
NSString *str2 = [array1 objectAtIndex:j];
if([str1 isEqualToString:str2])
{
//do something which you want i.e add the values to some other array
}
}
}
You should probably use NSSet for this purpose
NSSet *set1 = [NSSet setWithObjects:#"a", #"s", #"d", #"f", nil];
NSSet *set2 = [NSSet setWithObjects:#"a", #"s", nil];
NSMutableSet *notInSet1 = [NSMutableSet setWithSet:set2];
[notInSet1 minusSet:set1];
NSMutableSet *notInSet2 = [NSMutableSet setWithSet:set1];
[notInSet2 minusSet:set2];
NSMutableSet *symmetricDifference = [NSMutableSet setWithSet:notInSet1];
[symmetricDifference unionSet:notInSet2];
NSArray *array1 = [[NSArray alloc] initWithObjects:#"a",#"b",#"c",nil];
NSArray *array2 = [[NSArray alloc] initWithObjects:#"a",#"d",#"c",nil];
NSMutableArray *ary_result = [[NSMutableArray alloc] init];
NSMutableArray *ary_resultUnmatched = [[NSMutableArray alloc] init];
for(int i = 0;i<[array1 count];i++)
{
for(int j= 0;j<[array2 count];j++)
{
if([[array1 objectAtIndex:i] isEqualToString:[array2 objectAtIndex:j]])
{
[ary_result addObject:[array1 objectAtIndex:i]];
} else {
[ary_resultUnmatched addObject:[array1 objectAtIndex:i]];
}
}
}
NSLog(#"%#",ary_result);//it will print a,c
NSLog(#"%#",ary_resultUnmatched);//it will print b,d
so in else condition you'll have your un matched values

Sum duplicate on NSMutableArray

I have a NSMutableArray with objects of type NSMutableDictionary,
the NSMutableDictionary contains 2 keys
-Airlines (string)
-Rating (integer)
I have an NSMutableArray with all the objects and what i need is to Sum the rating of all the airline companies repeated objects, an example:
Airline Rating
A 2
B 3
B 4
C 5
The end result array will be the A = 2, C = 5 and the Sum of B´s that is equal to 7.
My code so far:
for (int i = 0; i < arrayMealRating.count; ++i) {
NSMutableDictionary *item = [arrayMealRating objectAtIndex:i];
NSLog(#"item=%#",item);
for (int j = i+1; j < arrayMealRating.count; ++j)
{
if ([[item valueForKey:#"Airline"] isEqualToString:[arrayMealRating objectAtIndex:j]]){
NSMutableDictionary *item = [arrayMealRating objectAtIndex:j];
NSMutableDictionary *item1 = [arrayMealRating objectAtIndex:i];
NSInteger auxCount = [[item valueForKey:#"setMealRating"] integerValue] + [[item1 valueForKey:#"setMealRating"] integerValue];
NSMutableDictionary *aux = [NSMutableDictionary dictionaryWithObjectsAndKeys:[item valueForKey:#"Airline"], #"Airline"
,[NSString stringWithFormat:#"%d",auxCount], #"setMealRating"
,nil];
NSLog(#"aux=%#",aux);
[arrayMealRating replaceObjectAtIndex:i withObject:aux];
}
}
}
A bit messy i know but i dont know how to work with NSMutableDictionary, any help will be much appreciated, Thanks in Advance!
Incase you dont want to change how your storing the data, heres how you would do it using key-value coding. Heres the dirrect link to the documentation for #distinctUnionOfObjects and #sum.
// Get all the airline names with no duplicates using the KVC #distinctUnionOfObjects collection operator
NSArray *airlineNames = [arrayMealRating valueForKeyPath:#"#distinctUnionOfObjects.Airline"];
// Loop through all the airlines
for (NSString *airline in airlineNames) {
// Get an array of all the dictionaries for the current airline
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(Airline == %#)", airline];
NSArray *airlineMealRating = [arrayMealRating filteredArrayUsingPredicate:predicate];
// Get the sum of all the ratings using KVC #sum collection operator
NSNumber *rating = [airlineMealRating valueForKeyPath:#"#sum.Rating"];
NSLog(#"%#: %#", airline, rating);
}
This gives the following output
A: 2
B: 7
C: 5
I would suggest to redesign that entirely if that's at all possible.
Create a class Airline
#interface Airline : NSObject
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSMutableArray *mealRatings;
- (void)addMealRating:(float)rating;
- (float)sumOfMealRatings;
#end
#implementation
- (id)initWithName:(NSString *)pName
{
self = [super init];
if (self)
{
self.name = pName;
self.mealRatings = [NSMutableArray array];
}
return self;
}
- (void)addMealRating:(float)rating
{
[self.mealRatings addObject:#(rating)];
}
- (float)sumOfRatings
{
float sum = 0;
for (NSNumber *rating in self.mealRatings)
{
sum += [rating floatValue];
}
}
#end
Then in your 'mainclass' you simply hold an NSArray with instances of your Airline objects. It might require you to change some of your existing code, but I think in the long run it saves you time and trouble. Perhaps you recognize later on, that you want to add additional properties to your Airlines. A dictionary is a cumbersome way to do that.
#try this
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:4];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:[NSNumber numberWithInteger:2] forKey:#"A"];
[myArray addObject:dict];
NSMutableDictionary *dict2 = [[NSMutableDictionary alloc] init];
[dict2 setValue:[NSNumber numberWithInteger:3] forKey:#"B"];
[myArray addObject:dict2];
NSMutableDictionary *dict3 = [[NSMutableDictionary alloc] init];
[dict3 setValue:[NSNumber numberWithInteger:4] forKey:#"B"];
[myArray addObject:dict3];
NSMutableDictionary *dict4 = [[NSMutableDictionary alloc] init];
[dict4 setValue:[NSNumber numberWithInteger:5] forKey:#"D"];
[myArray addObject:dict4];
NSMutableDictionary *resultDictionary = [[NSMutableDictionary alloc] init];
for(NSMutableDictionary *dictionary in myArray)
{
NSString *key = [[dictionary allKeys] objectAtIndex:0];
NSInteger previousValue = [[resultDictionary objectForKey:key] integerValue];
NSInteger value = [[dictionary objectForKey:key] integerValue];
previousValue += value;
[resultDictionary setObject:[NSNumber numberWithInteger:previousValue] forKey:key];
}
for(NSString *key in resultDictionary)
{
NSLog(#"value for key = %# = %d",key, [[resultDictionary valueForKey:key] integerValue]);
}

Help with Memory leak: init NSMutableArray from file

In some point in my app, I need to load a list from a file, so I implement this method to load the list:
-(void)loadList
{
NSString *filePath = [self dataFilePath]; //This is a method return the path of file
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSMutableArray *tempArray = [[NSMutableArray alloc]initWithContentsOfFile:filePath];
self.list = [[NSMutableArray alloc]initWithArray:tempArray];
[tempArray release];
}
}
The self.list is a (retain) property.
I think the leak is from [alloc] when I init the selfl.list. I used
self.list = [[[NSMutableArray alloc]initWithArray:tempArray]autorelease];
But the app crashes due to EXC_BAD_ACCESS. So I am confused here how to solve this.
Thanks for any suggestions.
Just assign,
self.list = tempArray;
As tempArray is already an array, you don't have to create another array from it. You ca directly assign to self.list.
There is no need to allocate another time for array .So just assign directly
-(void)loadList
{
NSString *filePath = [self dataFilePath]; //This is a method return the path of file
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSMutableArray *tempArray = [[NSMutableArray alloc]initWithContentsOfFile:filePath];
self.list = [tempArray copy];
[tempArray release];
}
}
Don't autorelease it. (I guess).
is your list property assign or retain?
if it is retain, then you should change this:
self.list = [[NSMutableArray alloc]initWithArray:tempArray];
to this:
self.list = [[NSMutableArray arrayWithArray:tempArray];

Autoreleased NSMutableArray not populated

I want to populate an array like this:
NSMutableArray *array = [self methodThatReturnsAnArray];
In the "methodThatReturnsAnArray"-method I create an array like this:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
When I'm finished populating "arrayInMethod" I'm returning the array and in order to prevent a memory leak I'm using:
return [arrayInMethod autorelease];
However the "array"-variable is never populated. When removing the "autorelease" it works fine though. What should I do in order to make sure that the returned object i released?
EDIT
+ (NSMutableArray *)buildInstants:(NSArray *)huntsArray {
NSMutableArray *goGetObjects = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [huntsArray count]; i++) {
NSDictionary *huntDict = [huntsArray objectAtIndex:i];
PHGoGet *goGet = [[PHGoGet alloc] init];
goGet.title = [huntDict objectForKey:#"title"];
goGet.description = [huntDict objectForKey:#"description"];
goGet.start = [huntDict objectForKey:#"start"];
goGet.end = [huntDict objectForKey:#"end"];
goGet.ident = [huntDict objectForKey:#"id"];
if ((CFNullRef)[huntDict objectForKey:#"image_url"] != kCFNull) {
goGet.imageURL = [huntDict objectForKey:#"image_url"];
} else {
goGet.imageURL = nil;
}
if ((CFNullRef)[huntDict objectForKey:#"icon_url"] != kCFNull) {
goGet.iconURL = [huntDict objectForKey:#"icon_url"];
} else {
goGet.iconURL = nil;
}
goGet.longitude = [huntDict objectForKey:#"lng"];
goGet.latitude = [huntDict objectForKey:#"lat"];
goGet.companyIdent = [huntDict objectForKey:#"company_id"];
[goGetObjects insertObject:goGet atIndex:i];
[goGet release];
}
return [[goGetObjects copy] autorelease];
}
Try using the convienence method for NSMutableArray... change:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
To...
NSMutableArray *arrayInMethod = [NSMutableArray array];
array will return an autoreleased object.
First of all, I recommend you not to return a NSMutableArray from any method. It's better to use NSArray for that to avoid some very difficult to debug problems. My proposition is:
You declare the mutable array and populate it:
NSMutableArray *arrayInMethod = [[[NSMutableArray alloc] init] autorelease];
Then you return an autoreleased copy:
return [[arrayInMethod copy] autorelease];
And finally, when you take the returned array, you make it mutable again (only if you need to change it):
NSMutableArray *array = [[self methodThatReturnsAnArray] mutableCopy];
When you're done with the array, you release it:
[array release];

EXC_BAD_ACCESS in viewDidLoad of FlipsideViewController

I'm trying to display some data on the flip side view of a utility template application but the application aborts at the end of viewDidLoad method. I'm very new to iOS and could do with a bit of guidance.
[super viewDidLoad];
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
NSString *thePath = [[NSBundle mainBundle] pathForResource:#"SavedData"ofType:#"plist"];
NSMutableDictionary *tempRootDictionary;
NSMutableArray *tempMutableArray;
if (thePath && (tempRootDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:thePath])) {
NSArray *keys = [tempRootDictionary allKeys];
int keysCount = [keys count];
tempMutableArray = [NSMutableArray arrayWithCapacity:keysCount];
for (int i=0; i<keysCount; i++) {
NSDictionary *dictionary = [tempRootDictionary objectForKey:[keys objectAtIndex:i]];
MyModelObject *aModelObject = [[MyModelObject alloc] init];
[aModelObject setName:[dictionary objectForKey:#"name"]];
[aModelObject setContext:[dictionary objectForKey:#"context"]];
[aModelObject setUsername:[dictionary objectForKey:#"username"]];
[aModelObject setPassword:[dictionary objectForKey:#"password"]];
[tempMutableArray addObject:aModelObject];
[aModelObject release];
[dictionary release];
}
} else {
return;
}
Help would be really appreciated,
Many thanks...
The only obvious problem I see in the code posted is this:
[dictionary release];
On the line that you set dictionary, you are only getting a reference to the object in tempRootDictionary and not a new alloc'd instance of it. So don't release it. Remove that line.