How to convert NSArray to NSMutableArray - objective-c

ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *tempPeoples=[[NSMutableArray alloc]init];
for(int i=0;i<nPeople;i++){
ABRecordRef i1=CFArrayGetValueAtIndex(allPeople, i);
[tempPeoples addObject:i1];
// [peoples addObject:i1];
}// end of the for loop
peoples=[tempPeoples copy];
This code gives exception b/c I want to convert NSMutableArray to NSArray
Please Help

The subject reads, "How to convert NSArray to NSMutableArray". To get an NSMutableArray from an NSArray, use the class method on NSMutableArray +arrayWithArray:.
Your code does not show the declaration for peoples. Assuming it's declared as an NSMutableArray, you can run into problems if you try to treat it as such. When you send the copy message to an NSMutableArray, you get an immutable object, NSArray, so if you try to add an object to a copied NSMutableArray, you will get an error.
CFArrayRef is toll free bridged to NSArray, so you could simplify your code this way:
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
//NSMutableArray *tempPeoples = [NSMutableArray arrayWithArray:(NSArray*)allPeople];
// even better use the NSMutableCopying protocol on NSArray
NSMutableArray *tempPeoples = [(NSArray*)allPeople mutableCopy];
CFRelease(allPeople);
return tempPeoples; // or whatever is appropriate to your code
In the above code tempPeoples is an autoreleased NSMutableArray ready for you to add or remove objects as needed.

This code gives exception b/c I want to convert NSMutableArray to NSArray
This is very unlikely. NSMutableArray is a derived class of NSArray, so copying in that direction isn't an issue.
Maybe you've got an error because you don't retain the array. arrayWithArray returns an autorelease object. Either use [tempPeoples copy] or [[NSArray alloc] initWithArray: tempPeoples];

Simply you can do that
NSArray *yourArray ; // Static Array
NSMutableArray* subArrayData = [yourArray mutableCopy];

Related

Why mutable object(NSMutableArray and NSMutableDictionary) required alloc- init?while we can directly assign value to immutable objects

//Mutable object...
//first initialize
NSMutablearray *arr=[[NSMutableArray alloc]init];
//then add value
[arr addobjects:#"iPhone",#"Android",nil];
//But we can assign value immutable array without initialize
NSArray *brr=#[#"iPhone",#"Android"];
There are many ways to initialize NSMutableArray. For example:
NSMutableArray *arr = [NSMutableArray arrayWithObjects: #"iPhone", #"Android", nil];
The #[] literal syntax is a fairly new addition to ObjC, and it returns an NSArray (non-mutable), which is why you can't assign it directly to an NSMutableArray. It's just syntactic sugar for [NSArray arrayWithObjects:count:]. If you want to use that syntax, you still can, though:
NSArray *brr = [#[#"iPhone",#"Android"] mutableCopy];
That's just the way the literal syntax is. In Objective-C, it creates an NSArray. If you really want to use the syntax but end up with a mutable array you can use a copy like this:
NSMutableArray *brr=#[#"iPhone",#"Android"].mutableCopy;
This system is much better in Swift, where it's just one value type called Array and you set mutability with either a var or a let
var myArray = ["iPhone", "Android"] // mutable
let myArray = ["iPhone", "Android"] // immutable
You object to the two-step process:
//first initialize
NSMutableArray *arr=[[NSMutableArray alloc]init];
//then add value
[arr addobjects:#"iPhone",#"Android",nil];
And you say you would rather write a literal array:
NSArray *brr=#[#"iPhone",#"Android"];
So combine them:
NSMutableArray* arr = [NSMutableArray arrayWithArray: #[#"iPhone",#"Android"]];
Because the literal's type is immutable. Also, you should remember NSMutableArray is a subclass of NSArray. You can assign an instance of subclass to its superclass, but not otherwise.

Got exception when i try to replace a Mutable Array item

i got this exception:
[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance
when i try to replace a specific element by another:
EDIT:
this is my whole code:
//declaring an AppDelegate instance
AppDelegate *myAppDelegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
//get the array in which we have stored all the choosed themes
NSMutableArray *aMutableArray=myAppDelegate.themesChoosed;
for (int i=0; i<[aMutableArray count]; i++) {
NSString *str=[NSString stringWithString:[aMutableArray objectAtIndex:i]];
if ([str isEqualToString:#"B1"]) {
[aMutableArray replaceObjectAtIndex:i withObject:#"B2"];
}
}
I maked sure that the B1 element does exist in the array.
What is happening to your NSMuatbleArray before you get into the for loop?
Is it a property? If so, what is the property declaration? Did you use copy?
If you implement a property like this:
#property (nonatomic, copy) NSMutableArray *myArray;
...then you can run into problems like this because the synthesized setter sends copy to the array, which results in an immutable copy. If this is the case, you need to implement your own setter that calls mutableCopy on the array (or just use retain instead and design your code a little differently).
EDIT:
Based on your comments below and the updated code, I'm sure the problem must be something to do with the array on the app delegate not being mutable.
Try this:
NSMutableArray *mutableThemeseChoosed = [NSMutableArray arrayWithArray:myAppDelegate.themesChoosed];
I just tried your code and it works fine.
NSMutableArray *aMutableArray = [NSMutableArray arrayWithObjects:[NSString stringWithString:#"A1"],[NSString stringWithString:#"B1"],[NSString stringWithString:#"B2"],[NSString stringWithString:#"A1"],[NSString stringWithString:#"A2"],[NSString stringWithString:#"A1"],[NSString stringWithString:#"A1"], nil];
NSLog(#"%#",aMutableArray);
for (int i=0; i<[aMutableArray count]; i++) {
NSString *str=[NSString stringWithString:[aMutableArray objectAtIndex:i]];
if ([str isEqualToString:#"B1"]) {
[aMutableArray replaceObjectAtIndex:i withObject:#"B2"];
}
}
NSLog(#"%#",aMutableArray);
Your problem is - as the error tells - that your mutable array is a NSArray (which is not mutable)
What you get out of myAppDelegate.themesChoosed; is likely a NSArray. Try the following: NSMutableArray *aMutableArray= [NSMutableArray arrayWithArray:myAppDelegate.themesChoosed];

Is this a correct declaration of an Array in Objective c?

NSArray *arr=[[[NSArray alloc]autorelease]autorelease];
Close, but no cigar.
If you want an autoreleased NSArray, you'd need to use:
NSArray *arr = [[NSArray alloc] init] autorelease];
That said, this will simply get you an empty immutable array, so you'll most likely want to populate it via one of the initWithObjects: style methods. (See the full NSArray class reference for more information.)
Or you can just declare it like this:
[NSArray array];
This gives you an autoreleased instance of the array.

How to append two NSMutableArray's in Iphone sdk or append an NSArray With NSMutableArray?

I need to append two NSMUtableArray's can any one suggest me how it possible?
My code is:
NSMutableArray *array1 = [appDelegate getTextList:1];
NSArray *array2 = [appDelegate getTextList:2];
[array1 addObjectsFromArray:array2];//I am getting exception here.
Anyone's help will be much appreciated.
Thanks all,
Lakshmi.
What's probably happening, is that your [appDelegate getTestList:1] is not actually returning a NSMutableArray, but a NSArray. Just typecasting the array as mutable by holding a pointer to it like that will not work in that case, instead use:
NSMutableArray *array1 = [[appDelegate getTextList:1] mutableCopy];
NSArray *array2 = [appDelegate getTextList:2];
[array1 addObjectsFromArray:array2];
Or you could store the 'textList' variable that you have in your appDelegate as an NSMutableArray in the first place. I am assuming that you have an NSArray of NSArrays (or their mutable versions). Eg.
// In the class interface
NSMutableArray *textLists;
// In the function in which you add lists to the array
NSMutableArray *newTextList;
[self populateArray:newTextList]; // Or something like that
[textLists addObject:newTextList];
Note: that you will probably have a different workflow, but I hope that you get the idea of storing the actual lists as NSMutableArrays.
Another Note: the second method WILL modify in place the NSMutableArray that [appDelegate getTextList:1]; returns
Try this:
NSMutableArray *result =
[[appDelegate getTextList:1] mutableCopy]
addObjectsFromArray:[appDelegate getTextList:2]];
You're getting the exception because you're trying to send mutating messages to an immutable array.

Terminology question regarding looping thru an NSArray in Objective-C

When you have an NSArray and you want to evaluate and change the elements, you can't change the array from inside the loop. So, you create a mutable copy that can be changed.
code example:
NSMutableArray *bin = [NSMutableArray arrayWithObjects:#"0", #"1", #"2", #"3", #"4", #"5", #"6", #"7", nil];
NSMutableArray *list = [NSMutableArray arrayWithObjects:#"a1", #"b2", #"c3", #"e4", nil];
NSMutableArray *listHolder = list; // can't mutate 'list' within loop so create a holder
for (int i = 0; i < [list count]; i++) {
[listHolder replaceObjectAtIndex:i withObject:[bin objectAtIndex:i]];
}
What is that second array listHolder called? I mean, what term is used to refer to an array in this context.
This is perfectly valid:
NSMutableArray *bin = [NSMutableArray arrayWithObjects:#"0", #"1", …, #"7", nil];
NSMutableArray *list = [NSMutableArray arrayWithObjects:#"a1", …, #"e4", nil];
// NSInteger should be used instead of int
for (NSInteger i = 0; i < [list count]; i++) {
[list replaceObjectAtIndex:i withObject:[bin objectAtIndex:i]];
}
You're not allowed to change the array inside a for … in or NSEnumerate loop, but using an index is perfectly valid.
What troubles me is your misunderstanding of pointers.
If it were a loop in which you weren't allowed to mutate the array this wouldn't copy the array but only the pointer to the array, effectively modifying the array you're not allowed to. (I'm not even sure if this works.)
Instead of just copying the pointer
// can't mutate 'list' within loop so create a holder
NSMutableArray *listHolder = list;
make a true copy:
NSMutableArray *copy = [[list mutableCopy] autorelease];
In case I really have to make a copy I try to name it according to its content. For example:
NSMutableArray *views;
NSMutableArray *reorderedViews = [views mutableCopy];
// reorder reorderedViews
Sometimes it's hard to find a good enough name, then I usually just use nameCopy.
In this context listHolder would be called a copy.
Your code has a bug though. This line is not actually making a copy, it is only letting listHolder and list both reference the same array object:
NSMutableArray *listHolder = list;
This would be an actual copy:
NSMutableArray *listHolder = [list mutableCopy];
Make sure that you use mutableCopy and not just copy if you want the copy to be mutable. The copy method will return immutable variants on all mutable classes such as NSMutableSet, NSMutableDictionary, and so forth.
Also as others have noted it is only inside the for (item in collection) loop that the enumerated collection can not be mutated. In a normal for (;;) mutation is perfectly ok, but can lead to strange result if the number of items in the collection changes.
There is not specific stylistic or common name for this that is universally used, it is your code afterall, and if there appropriate terms for them use them.
Having said that generally if you don't have specific names in this sort of situation then people refer to the original list as the "source" (src) and the final list as "destination" (dst), just like in a memory blitting style operation.
A temporary mutable copy of the original NSArray would be how I would refer to it.