-1

I am passing an array from one ViewController to another by [NSUserDefaults standardUserDefaults].and i am retrieving array in second view controller and while i try to update a string value it throws an Exception as below

Attempt to mutate immutable object with setString

and below is my code. Not able to track what is the issue .

NSMutableArray *sampleArray = [[NSMutableArray alloc]init];
sampleArray = [[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"] copy];
NSString *commentCount = [NSString stringWithFormat:@"%@",[[sampleArray valueForKey:@"totalComments"]objectAtIndex:Row]];
int cCount = [commentCount intValue];
[[[sampleArray valueForKey:@"totalComments"] objectAtIndex:Row]setString:[NSString stringWithFormat:@"%d",cCount+1]];

Thanks in Advance.

Grey_Code
  • 454
  • 1
  • 4
  • 20
  • Don't alloc init sampleArray just to override it the in next line. replace `NSMutableArray *sampleArray = [[NSMutableArray alloc]init];` with `NSMutableArray *sampleArray;` – The dude Jul 10 '14 at 11:56
  • i tried all answers. bad luck. getting same exception. any other way ? – Grey_Code Jul 10 '14 at 12:09
  • What kind of object is [sampleArray valueForKey:@"totalComments"] ? I guess it's an NSArray. What kind of objects contains this array? – The dude Jul 10 '14 at 12:12
  • Strings inside array. like :( 6, 0, 0, 35, 3, 0, 0, 0, 0, 0 ) – Grey_Code Jul 10 '14 at 12:26
  • [[sampleArray valueForKey:@"totalComments"] objectAtIndex:Row] line returns you NSString which is nonmutable. So first make it as mutable then use it. For help See my answer below. – Yogendra Jul 10 '14 at 12:35
  • Stupid question: **What line** was reported as causing the error??? – Hot Licks Jul 10 '14 at 12:36
  • Did you attempt to actually *read* the error message? What does it say? – Hot Licks Jul 10 '14 at 12:39
  • @HotLicks - Yes, i can understand. it says i am updating Mutable Object to Imutable Object. But i can't track where is that part happening ? – Grey_Code Jul 10 '14 at 12:49
  • Is says you're attempting change (mutate) an object that cannot be changed. And you're doing it with `setString`. Now, where in your code do you see `setString`? And what kind of object is it operating on? – Hot Licks Jul 10 '14 at 15:49
  • If `sampleArray` is an NSArray, why are you doing `valueForKey` on it? – Hot Licks Jul 10 '14 at 15:55
  • There are at least 5 errors in the above code. Please go back and learn the fundamentals a little bit better. – Hot Licks Jul 10 '14 at 15:57

4 Answers4

1

Your code:

    NSMutableArray *sampleArray = [[NSMutableArray alloc]init];
    sampleArray = [[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"] copy];
    NSString *commentCount = [NSString stringWithFormat:@"%@",[[sampleArray valueForKey:@"totalComments"]objectAtIndex:Row]];
    int cCount = [commentCount intValue];
    [[[sampleArray valueForKey:@"totalComments"] objectAtIndex:Row]setString:[NSString stringWithFormat:@"%d",cCount+1]];

1) You do

NSMutableArray *sampleArray = [[NSMutableArray alloc]init];
sampleArray = [[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"] copy];

The [[NSMutableArray alloc]init] constructs an empty mutable array. The subsequent sampleArray = [[[NSUserDefaults ... overwrites the pointer set in the prior line with a pointer to a different array. This is wasted motion (and creating an object is expensive). Thankfully for you there is ARC, or it would also represent a leaked object. It should be simply

 NSArray *sampleArray = [[NSUserDefaults ...

(Note it is not an NSMutableArray -- see below.)

2) You do

sampleArray = [[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"] copy];

The copy on the end unnecessarily takes the object returned by objectForKey and copies it. Unless here were some possibility of unwanted concurrent modification of the original array (which is impossible in this case), this copy operation is completely unnecessary and again an expensive operation.

3) You do

NSString *commentCount = [NSString stringWithFormat:@"%@",[[sampleArray valueForKey:@"totalComments"]objectAtIndex:Row]];

Doing [NSString stringWithFormat:@"%@",someValue] simply (and expensively) creates a copy of someValue. Again, this is totally unnecessary -- it only serves to make your statement longer and more confusing.

4) You do

[[[sampleArray valueForKey:@"totalComments"] objectAtIndex:Row]setString:[NSString stringWithFormat:@"%d",cCount+1]];

Let's take that (unnecessarily) long statement apart:

NSArray* temp1 = [sampleArray valueForKey:@"totalComments"];

This is using "key-value" coding and will examine every NSDictionary in the array and ask it for any "totalComments" element.

NSString* temp2 = [temp1 objectAtIndex:Row];

This takes the result from valueForKey and examines only the Row element. Though it's hard to know for sure without knowing how "commentsArray" is constructed, very likely it would have worked just as well (and more clearly) to access the Row element of sampleArray and then request the totalCommnts value from the resulting NSDictionary. This would have been faster and clearer.

What you now have in temp2 is an NSString. You now effectively execute

[temp2 setString:[NSString stringWithFormat:@"%d",cCount+1]];

Of course, your problem is now that an NSString is immutable, so an exception occurs. If you want to change it you must have an NSMutableString. But you cannot simply "install" one of those in the temp1 array, since all values returned by NSUserDefaults are immutable, including sampleArray, temp1, and temp2. (And, no, they cannot be made mutable by simply changing the declarations.)

So you're kind of stuck. You need to totally redesign this function.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • Ok, then again i have to set this updated temp2 string back to that array. that is my problem – Grey_Code Jul 11 '14 at 08:40
  • Ok, No Probs. Thanks for you all.i achieved this Process completely by different way. – Grey_Code Jul 11 '14 at 08:42
  • @Grey_Code - You can't set temp2 back into the dictionary because the dictionary is immutable (and because you don't know which dictionary to update due to how you found temp2 in the first place). If the string were mutable that would not matter, since updating the string pointed by temp2 would update the string in the dictionary. But of course the string is not mutable either. – Hot Licks Jul 11 '14 at 11:37
0

there is a problem in your code line

sampleArray = [[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"] copy];

because copy return non mutable array so you have to do like

sampleArray = [NSMutableArray arrayWithArray:[[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"];
Retro
  • 3,985
  • 2
  • 17
  • 41
-1
NSMutableArray *sampleArray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults]objectForKey:@"commentsArray"]];
NSString *commentCount = [NSString stringWithFormat:@"%@",[[sampleArray valueForKey:@"totalComments"]objectAtIndex:Row]];
int cCount = [commentCount intValue];
NSMutableString *myMutableString = [NSMutableString stringWithString:[[sampleArray valueForKey:@"totalComments"] objectAtIndex:Row]];
[myMutableString setString:[NSString stringWithFormat:@"%d",cCount+1]];
Yogendra
  • 1,728
  • 16
  • 28
  • "[[sampleArray valueForKey:@"totalComments"] objectAtIndex:Row]". Could you describe this line please. @Grey_Code – Yogendra Jul 10 '14 at 12:18
  • [[[sampleArray valueForKey:@"totalComments"]objectAtIndex:Row]setString:myMutableString]; – Grey_Code Jul 10 '14 at 12:43
  • Replace this line with 2 lines in my answer. – Yogendra Jul 10 '14 at 12:45
  • it will get string like if Row=2, then "0" is detected from Array. at this place i'm incrementing the count. and saving back the updated array to `NSUserDefaults`. – Grey_Code Jul 10 '14 at 12:45
  • Ok.next i have to update the incremented count string to array and save back to nsuserdefaults. – Grey_Code Jul 10 '14 at 12:46
  • Could you show me the content format of sampleArray. It'll help me to make my answer more help full to you. @Grey_Code – Yogendra Jul 11 '14 at 04:59
-1

The problem is that you are passing a mutable array value to a immutable string.Try changing NSString to NSMutableString.Hopefully this helps

v1shnu.mee
  • 122
  • 1
  • 1
  • 8