spen123
spen123

Reputation: 3524

Add Dictionary to NSMutableArray of Dictionaries

I have an NSMutableArray called myMutbaleArray that looks like this when I log it

2015-12-08 17:04:21.679 APP[3342:573379] (
{
  id = 19;
  "num_test" = 100000;
  url = "http://fsad.com";
},
{
  id = 20;
  "num_test" = 100001;
  url = "http://teeeet.com";
}
)

And I want to add an object that looks like this

{
  id = 21;
  "num" = 100002;
  url = "http://example.com";
}

So I am trying this

[myMutbaleArray addObject:@{ @"id":@"23",@"num_test":@"100000", @"url":mainDict[@"website_url"],@"website_name":@"website"}];

But when I do this I get

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

I initialize the array like this

@interface {
NSMutableArray *socailArray;
}
//inside connectionDidFinishLoading
socailArray = [dataDict valueForKey:@"socail"];

Why can I add another dictionary to the MutableArray?

Thanks

Upvotes: 0

Views: 657

Answers (3)

Nghia Luong
Nghia Luong

Reputation: 790

With socailArray = [dataDict valueForKey:@"socail"];, the type of [dataDict valueForKey:@"socail"] is NSArray, so it auto cast socailArray into NSArray, that's why you can not insert thing into this.

To avoid this, you must be hold socailArray as NSMutableArray using: socailArray = [[dataDict valueForKey:@"socail"] mutableCopy];

Hope this could help.

Upvotes: 0

Julian F. Weinert
Julian F. Weinert

Reputation: 7570

If you see this, your array is actually not a mutable array. Here is the hint:

-[__NSCFArray insertObject:atIndex:]
  ^^^^^^^^^^^

The object is of type __NSCFArray, which is an internal counterpart of NSArray.

Even if you declare your variable as NSMutableArray the pointer can point to an object of any type (event for example NSRegularExpression). Important is, how it is created.

This happens to most people if they serialise an array either using NSUserDefaults, NSJSONSerialization or what ever.

The key is to create a mutable copy when the array gets deserialised using

-[NSArray mutableCopy]

Note that this is not deep-copy. This means an array contained in the root array will not be mutable copied and needs to be replaced separately.

Deep copying can be achieved using this:

// array
NSArray *originalArray = @[@"a", @"b", @[@1, @2]];
NSMutableArray *mutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)originalArray, kCFPropertyListMutableContainers);

// dictionary
NSDictionary *originalDictionary = @{@"a": @"b", @"c": @[@{@"abc": @123}]};
NSMutableDictionary *mutableDictionary = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);

Upvotes: 1

vien vu
vien vu

Reputation: 4347

You should change init to:

//inside connectionDidFinishLoading
 socailArray  = [NSMutableArray arrayWithArray:[dataDict valueForKey:@"socail"]];

Because: [dataDict valueForKey:@"socail"] is a NSArray.

Upvotes: 0

Related Questions