NSMutableArray addObject getting set to nil after

2019-08-17 06:56发布

问题:

I have declared an NSMutableArray *arrAllRecordsM and am trying to add NSMutableDictionary *dicRecordM to it using addObject. The dicRecordM gets added to arrAllRecordsM but on doing [dicRecordM removeAllObjects] it sets to nil in arrAllRecordsM. Below is the code, please help me fix it.

self.arrAllRecordsM = [NSMutableArray array];
self.dicRecordM = [NSMutableDictionary dictionary];

// Some Method

[self.dicRecordM setObject:@"Test" forKey:@"ADDRESS"];
[self.arrAllRecordsM addObject:self.dicRecordM];

// Value: Test
NSLog(@"Value: %@", [[self.arrAllRecordsM objectAtIndex:0] valueForKey:@"ADDRESS"]);
[self.dicRecordM removeAllObjects];

// Value: null
NSLog(@"Value: %@", [[self.arrAllRecordsM objectAtIndex:0] valueForKey:@"ADDRESS"]); 

回答1:

Adding an object to an NSMutableArray just stores a pointer (or "strong reference") to the object into the array. Therefore

[self.arrAllRecordsM objectAtIndex:0]

and

self.dicRecordM

are two pointers to the same object. If your remove all key/value pairs from self.dicRecordM then [self.arrAllRecordsM objectAtIndex:0] still points to the same (now empty) dictionary. That is the reason why

[[self.arrAllRecordsM objectAtIndex:0] valueForKey:@"ADDRESS"]

returns nil.

If you want an independent copy of the dictionary in the array, use

[self.arrAllRecordsM addObject:[self.dicRecordM copy]];

copy can be used on many classes, such as NSDictionary, NSArray and NSString and their mutable variants, to get a "functionally independent object". Formally, it is available for all classes conforming to the NSCopying protocol.



回答2:

This is expected behavior. You removed all the objects from the dictionary by calling removeAllObjects, then tried to retrieve an object from it and rightfully getting nil, since it doesn't exist in the dictionay anymore (you removed it).

What's maybe unclear to you is that NSArray doesn't copy the element you add to it, instead it just holds a strong reference.

So both dicRecordM and arrAllRecordsM are holding a reference to the same object, hence any modification to it (in this case removeAllObjects) will affect the same dictionary.


Incidentally, you shouldn't use valueForKey: for accessing the dictionary's entries. Use objectForKey: or the shorter subscripted syntax. For instance

self.arrAllRecordsM[0][@"ADDRESS"]

You can read this answer Difference between objectForKey and valueForKey? as a reference, but the main problem is that valueForKey: can behave very differently from objectForKey: in case the key contains special KVC characters, such as @ or ..