Autoreleased NSMutableArray not populated - iphone

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];

Related

How to copy correctly a NSMutableArray?

I want to copy a NSMutableArray with the code below :
SectionArray *newSectionArray = [[SectionArray alloc] init];
NSMutableArray *itemsCopy = [self.sections mutableCopy];
newSectionArray.sections = [[NSMutableArray alloc] initWithArray:itemsCopy copyItems:YES];
But I have an error when I try to set an object in this new array :
[[self.sections objectAtIndex:intSection] replaceObjectAtIndex:intRow withObject:object];
[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance 0x7191720
I also tried :
SectionArray *newSectionArray = [[SectionArray alloc] init];
newSectionArray.sections = [[[NSMutableArray alloc] initWithArray:itemsCopy copyItems:YES] mutableCopy];
My SectionArray class :
#implementation SectionArray
#synthesize sections;
#synthesize value;
- initWithSectionsForWayWithX:(int)intSections andY:(int)intRow {
NSUInteger i;
NSUInteger j;
if ((self = [self init])) {
sections = [[NSMutableArray alloc] initWithCapacity:intSections];
for (i=0; i < intSections; i++) {
NSMutableArray *a = [NSMutableArray arrayWithCapacity:intRow];
for (j=0; j < intRow; j++) {
Node * node = [[Node alloc] initNodeWithX:i andY:j andValeur:0];
[a insertObject:node atIndex:j];
}
[sections addObject:a];
}
}
return self;
}
- (void)setObjectForNode:(Node *)object andX:(int)intSection andY:(int)intRow {
[[sections objectAtIndex:intSection] replaceObjectAtIndex:intRow withObject:object];
}
- (SectionArray *) copy {
...
}
#end
If I see it correctly then sections is a mutable array, but its elements
[sections objectAtIndex:intSection]
are immutable arrays, so you get the exception at
[[sections objectAtIndex:intSection] replaceObjectAtIndex:intRow withObject:object];
The reason is that you copy the items here (copyItems:YES):
newSectionArray.sections = [[NSMutableArray alloc] initWithArray:itemsCopy copyItems:YES];
so even if itemsCopy is an array of mutable arrays, the copies of these elements are immutable.
Added: For a "nested mutable copy" of your nested array you could procede as follows:
SectionArray *newSectionArray = [[SectionArray alloc] init];
newSectionArray.sections = [[NSMutableArray alloc] init];
for (NSUInteger i=0; i < [sections count]; i++) {
NSMutableArray *a = [[sections objectAtIndex:i] mutableCopy];
[newSectionArray.sections addObject:a];
}

Initialize multiple objects with different name

How can I Initialize and allocate multiple objects with different name and pass it to the NSArray. from Below code the object is initialized once in loop and I need to initialized multiple times as per the For loop will go with different name..and then pass it to NSArray.please check the code below..
when For loop will start means i=0 ..initialized item would betempItemi
now next time when i=1 and i=2 the tempItemi name will be same .how can i change this with in loop..and pass it to NSArray *items
for (int i = 0; i< [Array count]; i++)
{
id object = [Array objectAtIndex:i];
if ([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *objDict = (NSDictionary *)object;
ECGraphItem *tempItemi = [[ECGraphItem alloc]init];
NSString *str = [objDict objectForKey:#"title"];
NSLog(#"str value%#",str);
float f=[str floatValue];
tempItemi.isPercentage=YES;
tempItemi.yValue=f;
tempItemi.width=30;
NSArray *items = [[NSArray alloc] initWithObjects:tempItemi,nil];
//in array need to pass all the initialized values
[graph drawHistogramWithItems:items lineWidth:2 color:[UIColor blackColor]];
}
}
Why dont you just make the array mutable and then add the object each time like this:
NSMutableArray *items = [[NSMutableArray alloc] init];
// a mutable array means you can add objects to it!
for (int i = 0; i< [Array count]; i++)
{
id object = [Array objectAtIndex:i];
if ([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *objDict = (NSDictionary *)object;
ECGraphItem *tempItemi = [[ECGraphItem alloc]init];
NSString *str = [objDict objectForKey:#"title"];
NSLog(#"str value%#",str);
float f=[str floatValue];
tempItemi.isPercentage=YES;
tempItemi.yValue=f;
tempItemi.width=30;
[items addObject: tempItemi];
//in array need to pass all the initialized values
}
}
[graph drawHistogramWithItems:items lineWidth:2 color:[UIColor blackColor]];
Anyways items in your original code will be reinitializing each time and you are drawing a new histogram each time so your code won't work... This should work...
The code you have written is ok but,
NSArray *items will always contain only one item at each loop.
just declare that outside for loop as NSMutableArray,
and go with the same code you are using.
As you said you want to make variable dynamically as
ECGraphItem *tempItemi = [[ECGraphItem alloc]init];
here i will be changing in the loop,
You can create a NSDictionary with key/value as per with your tempItem1/2/3/4.... as key and save values by alloc/init.
Then instead of a variable tempItem32, you will be using [dict valueForKey:#"tempItem32"].
EDIT:
Check this example if this may come handy
NSMutableDictionary *dict=[NSMutableDictionary new];
for (int i=1; i<11; i++) {
NSString *string=[NSString stringWithFormat:#"string%d",i];
[dict setObject:[NSString stringWithFormat:#"%d", i*i] forKey:string];
}
NSLog(#"dict is %#",dict);
NSString *fetch=#"string5";
NSLog(#"val:%#, for:%#",[dict valueForKey:fetch],fetch);

Problem with a NSMutableArray Leak

I thought I knew how to deal with memory leaks and arrays, but then this pops up. I can't figure pout why this is leaking:
// MyViewController.h
NSMutableArray *myMutableArray;
#property (nonatomic, retain) NSMutableArray *myMutableArray;
// MyViewController.m
#synthesize myMutableArray;
- (void) viewDidLoad {
if (self.myMutableArray == nil) {
self.myMutableArray = [[NSMutableArray alloc] init];
}
. . .
for (NSUInteger i = 0; i < someCount; ++i) {
[self.myMutableArray addObject:[NSString stringWithFormat: #"%#",myString]];
}
}
- (void)viewDidUnload {
self.myMutableArray = nil
}
- (void)dealloc {
[myMutableArray release];
}
Your problem is here:
if (self.myMutableArray == nil) {
self.myMutableArray = [[NSMutableArray alloc] init];
}
It should be:
if (myMutableArray == nil) {
self.myMutableArray = [[[NSMutableArray alloc] init] autorelease];
}
Or:
if (myMutableArray == nil) {
myMutableArray = [[NSMutableArray alloc] init];
}
Explanation:
Since you are using retain as a property mutator attribute, the object will be retained when it is passed to the property setter, therefore you have a leak when you retain an object you already have ownership of.
The solution to this is to either a) Pass an autorelease-d object to the property setter or b) Assign the ivar directly to the alloc-ed object.
You're allocating a new array, then setting it to a retain property. Change that line to
self.myMutableArray = [NSMutableArray array];
self.myMutableArray = [[NSMutableArray alloc] init];
should be
self.myMutableArray = [[[NSMutableArray alloc] init] autorelease];
because myMutableArray is a retained property.

UISearchBar - search a NSDictionary of Arrays of Objects

I'm trying to insert a search bar in a tableview, that is loaded with information from a NSDictionary of Arrays. Each Array holds and object. Each object has several properties, such as Name or Address.
I've implemented the methods of NSSearchBar, but the code corresponding to the search it self, that i have working on another project where the Arrays have strings only, is not working, and I can't get to thr problem.
Here's the code:
'indiceLateral' is a Array with the alphabet;
'partners' is a NSDictionary;
'RLPartnersClass' is my class of Partners, each one with the properties (name, address, ...).
-(void)handleSearchForTerm:(NSString *)searchTerm {
NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init];
[self resetSearch];
for (NSString *key in self.indiceLateral) {
NSMutableArray *array = [partners valueForKey:key];
NSMutableArray *toRemove = [[NSMutableArray alloc] init];
for (NSString *name in array) {
if ([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location == NSNotFound)
[toRemove addObject:name];
}
if ([array count] == [toRemove count])
[sectionsToRemove addObject:key];
[array removeObjectsInArray:toRemove];
[toRemove release];
}
[self.indiceLateral removeObjectsInArray:sectionsToRemove];
[sectionsToRemove release];
[theTable reloadData];
}
Can anyone help me please?
Thanks,
Rui Lopes
I've done it.
Example:
-(void)handleSearchForTerm:(NSString *)searchTerm {
NSMutableDictionary *finalDict = [NSMutableDictionary new];
NSString *currentLetter = [[NSString alloc] init];
for (int i=0; i<[indiceLateral count]; i++) {
NSMutableArray *elementsToDict = [[[NSMutableArray alloc] init] autorelease];
currentLetter = [indiceLateral objectAtIndex:i];
NSArray *partnersForKey = [[NSArray alloc] initWithArray:[partnersCopy objectForKey:[indiceLateral objectAtIndex:i]]];
for (int j=0; j<[partnersForKey count]; j++) {
RLNames *partnerInKey = [partnersForKey objectAtIndex:j];
NSRange titleResultsRange = [partnerInKey.clientName rangeOfString:searchTerm options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0){
NSLog(#"found: %#", partnerInKey.clienteCity
[elementsToDict addObject:partnerInKey];
}
}
[finalDict setValue:elementsToDict forKey:currentLetter];
}
NSMutableDictionary *finalResultDict = [finalDict mutableDeepCopy];
self.partners = finalResultDict;
[finalResultDict release];
[theTable reloadData];
}

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.