Changes made in old array also reflecting in new copied array - objective-c

Copied the contents of an array to another array using mutableCopy, but if the changes made in original array it also show changes in new array. Below is code m using.
NSArray *newArr = [mainArray mutableCopy];
[[newArr objectAtIndex:indexpath.section] replaceObjectAtIndex:indexpath.row withObject:#""];
[[mainArray objectAtIndex:indexpath.section] removeObjectAtIndex:indexpath.row];
objAppDelegate.arrayProfile = [newArr objectAtIndex:2];
I have to remove the value from original array mainArray, but not want to reflect the changes in new array. Please guide.

For NSArray you have to use copy not mutablecopy
NSArray *newArr = [mainArray copy];

You need to copy all items of main array
NSMutableArray *newArr = [[NSMutableArray alloc] initWithCapacity:mainArray.count];
for (NSObject* item in mainArray) {
[newArr addObject:[item copy]];
}

Related

NSArray copy for undo /redo purposes

If I have an nsarray full of custom objects and I make a second array using:
NSArray *temp = [NSArray arrayWithArray:original];
then work with some properties of the objects inside the original array, then decide to roll back, I am then using the reverse:
original = [NSArray arrayWithArray:temp];
I am finding the objects I changed in the array also effected my temp array. I also tried implementing copyWithZone on my custom class, and using copyItems and it did not help. What else should I try?
To be clear, in order to use copyWithZone, I changed my array creation command to:
NSArray *temp = [[NSArray alloc] initWithArray:original copyItems:YES];
My copyWithZone:
-(id)copyWithZone:(NSZone *)zone{
CustomObject *ret = [[CustomObject allocWithZone: zone] init];
//copy properties
return ret;
}

Adding multiple values to an NSString from an array

I have an array of items, each with their own unique descriptions. Basically, I want to create a method which takes each item from the array and returns a single descriptive string which shows the description of each item in said array.
- (NSString *) itemList
{
NSString *list = [[NSString alloc] init];
for (Item *i in _items)
{
/**
Unsure :S
*/
[NSString stringWithFormat:#"%#: %#.\n", [i firstId], [i name]];
}
return list;
}
Basically, this is the coded logic that I have so far.
Assume I have two items which are initialised as such:
Item *testItem1 = [[Item alloc] initWithIdentifiers:#[#"shovel", #"spade"] name:#"a shovel" andDesc:#"This is a mighty fine shovel"];
Item *testItem2 = [[Item alloc] initWithIdentifiers:#[#"gem", #"crystal"] name:#"a gem" andDesc:#"This is a shiny gem"];
I then add those items to my Inventory object:
[testInventory put:testItem1];
[testInventory put:testItem2];
By calling the Inventory method itemList
[testInventory itemList];
on my inventory (code listed above), I want the following result:
#"shovel: a shovel.\ngem a gem."
Does anyone have any suggestions or pointers. I'm sure it's simple; it's just that I've only recently picked up Obj - C :)
Thanks
You can just use:
list = [list stringByAppendingFormat:#"%#: %#\n", [i firstId], [i name]];
or try NSMutableString:
NSMutableString *list = [[NSMutableString alloc] init];
[list appendFormat:#"%#: %#\n", [i firstId], [i name]];
You can do it more elegantly by overriding the description method for your Item class like this:
- (NSString *) description {
return [NSString stringWithFormat:"%#: %#.", [self firstId], [self name]];
}
and then to generate the string for all the items in the array:
NSString* itemsString = [itemList componentsJoinedByString:#"\n"];
I like adding the collection of strings to a mutable array and then calling componentsJoinedByString. It works even more cleanly if it is the description method you want on each object because you don't have to do the collecting loop first.
Create nsmutablearray
For each item in list
Nsmutablearray add object item.property
Return nsmutablearray componentsJoinedByString #", "
If you want the item's description though, you can just do, assuming you have an array with the objects already
TheArray componentsJoinedByString #", "

Cannot change mutable array?

Ok so I have been stuck on this for a while even though it's a simple problem, I am trying to add an NSDictionary to an array however when calling the addObject method on the array the program crashes claiming I am sending a mutating method to an immutable object.
my code looks like:
- (IBAction)btnSaveMessage:(id)sender {
//Save The Message and Clear Text Fields
NSMutableDictionary *newMessageDictionary = [[NSMutableDictionary alloc] init];
[newMessageDictionary setObject:#"plist test title" forKey:#"Title"];
[newMessageDictionary setObject:#"plist subtitle" forKey:#"Subtitle"];
[newMessageDictionary setObject:#"-3.892119" forKey:#"Longitude"];
[newMessageDictionary setObject:#"54.191707" forKey:#"Lattitude"];
NSMutableArray *messagesArray =[[NSMutableArray alloc]init];
//Load Plist into array
NSString *messagesPath = [[NSBundle mainBundle] pathForResource:#"Messages"
ofType:#"plist"];
messagesArray = [NSArray arrayWithContentsOfFile:messagesPath];
[messagesArray addObject:newMessageDictionary]; //this causes crash
//write messagesarray to file
NSString *plistPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) lastObject];
plistPath = [plistPath stringByAppendingPathComponent:#"usersMessages.plist"];
[messagesArray writeToFile:plistPath atomically:YES];
So I understand that I am trying to add to what the compiler see's as an immutable array but I declared it as Mutable?
Whats going on? :(
You are re-initializing messagesArray with
[NSArray arrayWithContentsOfFile:messagesPath]
Making it not mutable. Try:
[NSMutableArray arrayWithContentsOfFile:messagesPath];
You are overwriting your NSMutableArray with an NSArray in this line
messagesArray = [NSArray arrayWithContentsOfFile:messagesPath];
The class method arrayWithContentsOfFile: is returning just an NSArray and not an NSMutableArray.
If you want the content of the file mutable you can do this:
NSMutableArray *messagesArray = [[NSArray arrayWithContentsOfFile:messagesPath] mutableCopy];
and you can remove the previous declaration
NSMutableArray *messagesArray =[[NSMutableArray alloc]init];
now.

Remove object from NSMutableArray after parsing JSON

The JSON source formatted with jsonviewer.stack.hu:
My Parse Method (simplified):
- (void)parseMethod {
// OTHER STUFF
arrayList = [[NSMutableArray alloc] init];
NSURL *url2 = // THE URL SOURCE OF JSON OBJECT, ON A REMOTE SERVER
NSURLRequest *request2 = [NSURLRequest requestWithURL:url2 cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0];
AFJSONRequestOperation *operation2 = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request2
success:^(NSURLRequest *request2, NSHTTPURLResponse *response2, id JSON)
{
arrayList = [JSON objectForKey:#"list"];
// HERE I TRIED TO WRITE [arrayListPrev removeObjectAtIndex:0];
NSMutableArray *arrayList1 = [arrayList valueForKey:#"list1"];
}
failure:^(NSURLRequest *request2, NSHTTPURLResponse *response2, NSError *error2, id JSON2) {
}];
[operation2 start];
}
The problem:
After the parsing I want to remove the FIRST OBJECT of array named "list", because I must populate the rows of a UITableView with all the values of list1 in the arrays EXCEPT the first ( list array->array number 0->list1 value of 0 ). I have tried the code:
[arrayList removeObjectAtIndex:0];
In several position but app crashes with error:'-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'... so what's the best way to REMOVE the FIRST object (array number 0) from that NSMutableArray *list AFTER the parsing, to ELIMINATE The list1 value of 0 object? Thanks!
In spite of you write arrayList = [[NSMutableArray alloc] init];
Here, as i guess, you assign simple immutable array instance
arrayList = [JSON objectForKey:#"list"];
You can do this instead:
arrayList = [[JSON objectForKey:#"list"] mutableCopy];
[arrayList removeObjectAtIndex:0];
The problem is that you are working with an NSArray and not an NSMutableArray. This is probably due to the fact your parser returns immutable objects. What you need to do is take that NSArray, create an NSMutableArray with it and then remove the first object
NSMutableArray *_arrayList = [NSMutableArray arrayWithArray:arrayList];
[_arrayList removeObjectAtIndex:0];
// dont forget to store your array wherever you need it
The Error shows that your array is having value of immutable type.Use a mutable copy or initialize your arrayList with -arrayWithArray: method.Hope it fixes the problem.
Note: allocate NSMutableArray to initialize with initWithCapacity method
As other's have suggested, you're working with an NSArray, which is not Mutable (Editable). I'm going to add my input though with a new function:
NSMutableArray *mutableArrayList = [arrayList mutableCopy];
This creates a mutable copy of the array.

Can someone explain to me what's going on here?

I'm going to paste the code below, then tell you what I've tried to determine from the code.
If you're reading this quickly, start with the text right above the next code-block.
- (void)tableViewDidLoadModel:(UITableView*)tableView {
self.items = [NSMutableArray array];
self.sections = [NSMutableArray array];
NSMutableDictionary *groups = [NSMutableDictionary dictionary];
for (int c = 0;c < [_contacts.people count];c++) {
NSDictionary *person = [_contacts.people objectAtIndex:c];
NSString *name = [person objectForKey:#"fullName"];
NSString *letter = [name substringToIndex:1];
NSMutableArray *section = [groups objectForKey:letter];
NSLog(#"%# - %# - %#", name, [person objectForKey:#"index"], [person objectForKey:#"abId"]);
if (!section) {
section = [NSMutableArray array];
[groups setObject:section forKey:letter];
}
TTTableItem *item = [ttItem itemWithText:name URL:[person objectForKey:#"index"]];
[section addObject:item];
}
Someone else wrote this block of code. From what I can determine, they're trying to take the user's contacts and fill a TableView.
Now my real question has to do with that last line:
TTTableItem *item = [ttItem itemWithText:name URL:[person objectForKey:#"index"]];
[section addObject:item];
This is using the Three20 framework. Apparently what the previous developer did was use TTTableItem to kind of get a pre-formatted UITableViewCell. (Hopefully I'm thinking right?)
I need to replace this line of code with something normal.
I've thought of just using UITableViewCell, but other than that I'm not really sure how to start?
-tableViewDidLoadModel: is a method that comes from the TTTableViewDataSource protocol, so if you're trying to remove Three20 from your project, you've got more to do than just replace the TTTableItem.
TTTableItem is a subclass of NSObject, and the only thing it seems to add is a userInfo property. To get rid of it, you could start by creating your own class with the same property.