2

I'm new to ObjectiveC and Xcode and make mistakes. This bit of code gets a dictionary (myDataPlist) from getAllRecords. I then make a mutable copy of a dictionary (1 record) within (myDataPlist) and decrypt 1 field with it. This works perfectly. I return just that record (mutCopy). This works also. My problem is the original dictionary (myDataPlist) changes. It The record that is decrypted is also decrypted in (myDataPlist). The 2 NSLog(@"%@",myDataPlist) return different results. I must be missing something. Why is (myDataPlist) changing?

Thanks for the help.

-(NSDictionary *)getRecordForKey:(NSString *)key{

    NSDictionary *myDataPlist = [self getAllRecords];
    NSMutableDictionary *mutCopy = [[myDataPlist valueForKey:key] mutableCopy];
    NSArray *keys = [mutCopy allKeys];
    NSData *tData = [[NSData alloc]init];
    NSLog(@"%@",myDataPlist);
    for (int x = 0; x <= [keys count] - 1; x++) {
        if (![keys[x] isEqualToString:@"Template"] && ![keys[x] isEqualToString:@"RecNum"]) {

        NSMutableArray *myArray = [mutCopy objectForKey:keys[x]];
        tData = myArray[1];
        NSString *tString = [tData decryptData:tData withKey:self.settingsManager.masterPad];
        myArray[1] = tString;
        [mutCopy setObject:myArray forKey:keys[x]];

        }
    }
    NSLog(@"%@",myDataPlist);
    return mutCopy ;
}

1 Answers1

3

mutableCopy creates a copy of the dictionary only and not the contents of it. So the dictionary that you receive from [[myDataPlist valueForKey:key] mutableCopy] is essentially a new dictionary with references to the same objects (it's not a deep copy).

Try using

NSMutableDictionary *mutCopy = 
    [[NSMutableDictionary alloc] initWithDictionary:[myDataPlist valueForKey:key] 
                                          copyItems:YES];

instead of mutableCopy.

From Apple documentation:

otherDictionary

A dictionary containing the keys and values with which to initialize the new dictionary.

flag

If YES, each object in otherDictionary receives a copyWithZone: message to create a copy of the object—objects must conform to the NSCopying protocol. In a managed memory environment, this is instead of the retain message the object would otherwise receive. The object copy is then added to the returned dictionary. If NO, then in a managed memory environment each object in otherDictionary simply receives a retain message when it is added to the returned dictionary.

If your dictionary contains custom objects, make sure that they conform to the NSCopying protocol.

matt
  • 515,959
  • 87
  • 875
  • 1,141
Suhas
  • 1,500
  • 11
  • 15
  • I tried this and it causes an exception on the line myArray[1] = tString. Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object – Camillo Scarcella Apr 23 '13 at 02:51
  • I must have seen that coming!!! :) This is happening because the array is no longer mutable. Replace NSMutableArray *myArray = [mutCopy objectForKey:keys[x]]; with NSMutableArray *myArray = [NSMutableArray arrayWithArray:[mutCopy objectForKey:keys[x]]];. That should get you going. – Suhas Apr 23 '13 at 03:16
  • You could also try the solution provided in this question http://stackoverflow.com/questions/5453481/how-to-do-true-deep-copy-for-nsarray-and-nsdictionary-with-have-nested-arrays-di – Suhas Apr 23 '13 at 03:27
  • Thank you, this absolutely fixed my problem and I actually understand most of it, though I don't know why myArray became immutable. I'll figure it out. Again, thank you very much – Camillo Scarcella Apr 23 '13 at 21:10