Deep copy of iOS object array (NSCoding protocol)

Posted by Mr Mako on Sat, 15 Jun 2019 00:18:15 +0200

During the project, I encountered the use of object arrays: Contact Interface, which requires partition display. If I store an array and then rearrange it every time I display, I find that there will be a computing delay. All of my partitions are first placed in a dictionary in a singleton class. When I needed to use the contact's interface to define an additional NSDictionary assignment to it, trying to modify NSDictionary, I found that the array objects stored in the singleton class had also been modified. I feel very speechless. At that time, my nesting was like this.

NSDictionary@{key1:NSMutableArray @ [Object 1, Object 2],key2:NSMutableArray @ [Object 3, Object 4],...}

It is in a single case class that the attribute of an immutable dictionary NSDictionary is defined and n variable arrays NSMutableArray are stored, which can dynamically increase or delete the objects stored in the array.

On the Internet, I saw deep copies of many objects and shallow copies of copy/mutableCopy. And I have implemented the NSCoding protocol. But all of them were found to be ineffective. So I wrote a Test project and found a problem.

 NSArray *array1 = [NSArray arrayWithObjects:@"a", nil];

 NSMutableArray *arry2 = [array1 mutableCopy];

 [arry2 replaceObjectAtIndex:0 withObject:@"b"];

 NSLog(@"%@",array1);

So the output is still @[a]

But when I define two Person objects that implement the NSCoding protocol and have a name attribute and put them in an array

Person *person1 = [[Person alloc] init];
    person1.name = @"a";

    NSArray *array1 = [NSArray arrayWithObjects:person1, nil];

    NSArray *arry2 = [NSArray arrayWithArray:array1];

    [arry2 enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        Person *person = obj;
        person.name = @"c";
    }];

    NSLog(@"%@",array1);

The output Person's name is c
Some people say that if you want to copy objects in an array in depth, you have to rebuild an array and then give a new array in a loop, that is:

Person *person1 = [[Person alloc] init];
    person1.name = @"a";

    NSArray *array1 = [NSArray arrayWithObjects:person1, nil];

    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:0];
    [array1 enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        Person *person = [obj copy];
        person.name = @"c";
        [arrayM addObject:person];
    }];

    NSLog(@"%@",array1);

And the object must copy when traversing, otherwise it is difficult to achieve deep copy.
Later, another method was found by [NSKeyed Unarchiver unarchiveObjectWithData:[NSKeyed Archiver Archived Data WithRootObject:];

Person *person1 = [[Person alloc] init];
    person1.name = @"a";

    Person *person2 = [[Person alloc] init];
    person2.name = @"b";

    NSArray *array1 = [NSArray arrayWithObjects:person1, nil];

    NSArray *array2 = [NSArray arrayWithObjects:person2, nil];

    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:array1,@"a",array2,@"b", nil];

    [Object shareObject].dict = dict;

    NSLog(@"1:%@",[Object shareObject].dict);

    NSDictionary *temDict = [[Object shareObject].dict mutableCopy];

    NSMutableArray *arrayM = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:[temDict objectForKey:@"a"]]];

    [arrayM enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        Person *person = obj;
        person.name = @"c";
    }];

    NSLog(@"2:%@",[Object shareObject].dict);

And no matter how many layers you nest, as long as each layer implements the NSCoding protocol, deep copy can also be achieved. Later, I abandoned putting contacts in singleton classes and placed them directly in local files.

Topics: Attribute