How to copy correctly a NSMutableArray? - iphone

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

Related

copying three different array to one array

I have three array..say array1,array2,array3. All these arrays contains dictionary.Now, I want to copy all the objects of these array into a single array and display in table view.
My problem is that how will I copy those three array into 1.
Say;
NSMutableArray *array1 = [NSMutableArray arrayWithObject:Dict1];
NSMutableArray *array2 = [NSMutableArray arrayWithObject:Dict2];
NSMutableArray *array3 = [NSMutableArray arrayWithObject:Dict3];
Now, I want to copy the contains of array1, array2, array3 into array4.How will I do this.
Use this
NSMutableArray *array4 = [[NSMutableArray alloc] init];
[array4 addObjectsFromArray:array1];
[array4 addObjectsFromArray:array2];
[array4 addObjectsFromArray:array3];
//Do something on array4
[array4 release];
NSMutableArray *allObjs = [[NSMutableArray alloc] initWithArray: array1];
[allObjs addObjectsFromArray: array2];
[allObjs addObjectsFromArray: array3];
NSMutableArray *array4 = [[NSMutableArray alloc] init];
for (int i = 0; i < [array1 count]; i++)
{
[array4 addObject:[array1 objectAtIndex:i]];
}
for (int i = 0; i < [array2 count]; i++)
{
[array4 addObject:[array2 objectAtIndex:i]];
}
for (int i = 0; i < [array3 count]; i++)
{
[array4 addObject:[array3 objectAtIndex:i]];
}
//use your array4
[array4 release];
NSMutableArray * array4 = [NSMutableArray arrayWithObjects:[array1 objectAtIndex:0], [array2 objectAtIndex:0], [array3 objectAtIndex:0]];

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

How to properly release a NSMutableArray with objects that have a NSMutableArray member with NSNumber objects inside?

I'm puzzled about iOS memory management. I have a class that has a member of type NSMutableArray. When storing objects of this type in another array and removing them, Instruments shows that all those members leak memory. Here's the definition of my rogue class:
#interface Tester : NSObject {
int some;
NSMutableArray* others;
}
#property int some;
#property (nonatomic, retain) NSMutableArray* others;
-(id)init;
-(id)copy;
-(void)dealloc;
#end
Here's the implementation of the rogue class:
#implementation Tester
#synthesize some;
#synthesize others;
-(id)init {
self = [super init];
if(self) {
some = 0;
others = [[NSMutableArray alloc] initWithCapacity:5];
int i;
for(i = 0; i < 5; ++i) {
[others addObject:[NSNumber numberWithInt:i]];
}
}
return self;
}
-(id)copy {
Tester* cop = [[Tester alloc] init];
cop.some = some;
cop.others = [others mutableCopy]
return cop;
}
-(void)dealloc {
[others removeAllObjects];
[others release];
[super dealloc];
}
#end
And here's how I test it:
NSMutableArray* container = [[NSMutableArray alloc] init];
Tester* orig = [[Tester alloc] init];
int i;
for(i = 0; i < 10000; ++i) {
Tester* cop = [orig copy];
[container addObject:cop];
}
while([container count] > 0) {
[[container lastObject] release];
[container removeLastObject];
}
[container release];
Running this code leaks memory and Instruments shows that the leaked memory is allocated at line:
cop.others = [others mutableCopy];
What have I done wrong?
You are creating a copy: [others mutableCopy] which you own but forget to release. The line should be:
cop.others = [[others mutableCopy] autorelease];
You testing code would be clearer if you'd let the container array be the sole owner of the Tester objects:
NSMutableArray* container = [[NSMutableArray alloc] init];
Tester* orig = [[Tester alloc] init];
for (int i = 0; i < 10000; ++i)
[container addObject:[[orig copy] autorelease]];
while([container count] > 0)
[container removeLastObject];
[container release];
Now you could remove the loop that empties the container.
Or you could just skip the container:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Tester* orig = [[[Tester alloc] init] autorelease];
for (int i = 0; i < 10000; ++i)
[[orig copy] autorelease];
[pool drain]; // At this point all Tester objects are released
cop.others = [others mutableCopy]
Others is declared as a retained property, so assigning to it establishes an ownership claim on the new value. -mutableCopy is a method that implies ownership (because it contains the word "copy"). So you now have two claims of ownership, both of which must be released. The recommended way to do this is to assign the copy first to a temp variable, then assign that to your property and release it, like so:
NSMutableArray *tmpArray = [others mutableCopy];
cop.others = tmpArray;
[tmpArray release];
You could also do this in one step, avoiding the temp object, although doing so uses the autorelease pool and is slightly less efficient because of that:
cop.others = [[others mutableCopy] autorelease];

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

how to remove duplicate value in NSMutableArray

i'm scanning wifi info using NSMutableArray, but there are few duplicate values appear, so i try to use following code but still getting the duplicate values,
if([scan_networks count] > 0)
{
NSArray *uniqueNetwork = [[NSMutableArray alloc] initWithArray:[[NSSet setWithArray:scan_networks] allObjects]];
[scan_networks removeAllObjects];
NSSortDescriptor *networkName = [[[NSSortDescriptor alloc] initWithKey:#"SSID_STR" ascending:YES] autorelease];
NSArray *descriptors = [NSArray arrayWithObjects:networkName,nil];
[scan_networks addObjectsFromArray:[uniqueNetwork sortedArrayUsingDescriptors:descriptors]];
}
how this can be resolve, thanks
You can use NSSET but if you it is only used when order doesn't matter if order matter then go for this approach.I have used it and it give perfect answer. in Place of NSmutableArray array put your NSmutableArray which contains duplicate Value.
NSArray *copy = [NSmutableArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator])
{
if ([NSmutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound)
{
[NSmutableArray removeObjectAtIndex:index];
}
index--;
}
[copy release];
You should be using an NSMutableSet in the first place.
For eliminating all double entries in an array, see this question:
Make NSMutableArray or NSMutableSet unique.
Here is the code of removing duplicates values from NSMutable Array..it will work for you.
myArray is your Mutable Array that you want to remove duplicates values..
for(int j = 0; j < [myArray count]; j++){
for( k = j+1;k < [myArray count];k++){
NSString *str1 = [myArray objectAtIndex:j];
NSString *str2 = [myArray objectAtIndex:k];
if([str1 isEqualToString:str2])
[myArray removeObjectAtIndex:k];
}
}
// Now print your array and
I think its better to do this:
NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc]init];
for(int j = 0; j < [myArray count]; j++) {
for( k = j+1;k < [myArray count];k++) {
NSString *str1 = [myArray objectAtIndex:j];
NSString *str2 = [myArray objectAtIndex:k];
if([str1 isEqualToString:str2])
[indexes addIndex:k];
}
}
[myArray removeObjectsAtIndexes:indexes];
You can run into problems if you manipulate the array while looping in my experience.
This is another way:
- (NSArray *)removeDuplicatesFrom:(NSArray *)array {
NSSet *set = [NSSet setWithArray:array];
return [set allObjects];
}
maybe you can try the NSArray category.
#import <Foundation/Foundation.h>
#interface NSArray(filterRepeat)
-(NSArray *)filterRepeat;
#end
#import "NSArray+repeat.h"
#implementation NSArray(filterRepeat)
-(NSArray *)filterRepeat
{
NSMutableArray * resultArray =[NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (![resultArray containsObject: obj]) {
[resultArray addObject: obj];
}
}];
return resultArray;
}
#end