A Brief analysis of shallow copy and deep copy of iOS copy and mutableCopy

  • 2020-06-03 08:32:17
  • OfStack

ios provides copy and mutablecopy methods. As the name implies, copy is an object that copies 1 imutable, while mutablecopy is an object that copies 1 mutable.

Differences between copy and retain:

copy is to create 1 new object, retain is to create 1 pointer, reference object count plus 1. The Copy attribute means that the contents of the two objects are the same, the new object retain is 1, and it is independent of the reference count of the old object, which has not changed. copy reduces the dependency of objects on context.

The retain attribute means that two objects have the same address (create 1 pointer, copy the pointer), the content is of course the same, the retain value of this object +1 means that retain is a copy of the pointer and copy is a copy of the content.

Of course, not all objects in iOS support copy, mutableCopy, NSCopying compliant classes can send copy messages, NSMutableCopying compliant classes can send mutableCopy messages. An exception occurs if an copy or mutableCopy is sent without complying with both appellate protocols. However, the default ios class does not adhere to either of these protocols. If you want to customize 1 copy you must comply with NSCopying and implement copyWithZone: method, if you want to customize 1 mutableCopy you must comply with NSMutableCopying and implement mutableCopyWithZone: method.

First of all, we need to have the following premise:

[array addObject: obj];

This increases the reference count of obj by 1 and decreases the reference count of obj by 1 if remove is used.

This is what ios does with collections in memory.

Then, suppose that obj is only owned by array:

id temp = [array objectAtIndex:0];
[array removeObjectAtIndex: 0];

If you use temp again, an error will occur because obj has already been released.

(Note 1: if testing with NSString, note that @" abc "is constant :-))

Since the collection class is often encountered in the program, simple retain is not enough, you need to copy the contents of the collection, that is, a deep copy.

So let's talk about 1.

Ios provides copy and mutablecopy methods. As the name implies, copy copies an OBJECT of imutable, while mutablecopy copies an object of mutable.

Here are a few examples to illustrate.

1. Non-container class objects of the system

This refers to objects of class NSString,NSNumber, and so on.


  NSString *string = @"origion";
  NSString *stringCopy = [string copy];
  NSMutableString *stringMCopy = [string mutableCopy];
  [stringMCopy appendString:@"!!"];

A look at the memory reveals that string and stringCopy point to the same block of memory (also known as apple weak reference weak reference), where the reference count of stringCopy and the sample of string are both 2. stringMCopy, on the other hand, is what we call a true copy, allocating new memory, but pointing to the same string as string.

Here's another example:


NSMutableString *string = [NSMutableString stringWithString: @"origion"];
NSString *stringCopy = [string copy];
NSMutableString *mStringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
[mStringCopy appendString:@"mm"];//error
[string appendString:@" origion!"];
[stringMCopy appendString:@"!!"];

Each of the four NSString objects has a different memory allocation. However, for mStringCopy it is actually an imutable object, so the above error will be reported.
For non-container class objects of the system, we can think of copy as pointer copy (shallow copy) and mutableCopy as object copy (deep copy) if copied to 1 immutable object. If it is a copy of a mutable object, it is a deep copy, but the object returned by copy is immutable.

2. Container class objects of the system

NSArray, NSDictionary, etc. The same is true for the container class itself, where you need to look at what happens to objects inside the container after they are copied.


//copy Returns an immutable object, mutablecopy Return a mutable object 
NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSArray *arrayCopy1 = [array1 copy];
//arrayCopy1 Is and array with 1 a NSArray Object (points to the same object), including array The elements inside also point to the same pointer 
NSLog(@"array1 retain count: %d",[array1 retainCount]);
NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]);
NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
//mArrayCopy1 is array1 The mutable copy, the object to point to, and array1 Student: Different, but the elements and array1 The element in theta points to the same 1 An object. mArrayCopy1 You can also modify your own objects 
[mArrayCopy1 addObject:@"de"];
[mArrayCopy1 removeObjectAtIndex:0];

array1 and arrayCopy1 are pointer copies, while mArrayCopy1 is object copies. mArrayCopy1 can also change the period of elements: delete or add. Note, however, that the contents of the element in the container are pointer copies.

Let's test 1 with another example.


NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *mArrayCopy2 = [mArray1 copy];
NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
//mArrayCopy2,mArrayMCopy1 and mArray1 It's all pointing to no 1 Object, but all of its elements are 1 The same object 1 A pointer to the 
//1 Do the test under 
NSMutableString *testString = [mArray1 objectAtIndex:0];
//testString = @"1a1";// That will change testString The pointer is actually going to @ " 1a1 "Temporary object is assigned to testString
[testString appendString:@" tail"];// More than this 3 The first element of each array has been changed 

As you can see, the element object is always a pointer copy for the container. If you want the element object to be an object copy, you need to implement a deep copy.


http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"],[NSStringstringWithString:@"b"],@"c",nil];
NSArray *deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject: array]];

trueDeepCopyArray is a full deep copy, but deepCopyArray is not. For immutable elements within deepCopyArray it is a pointer copy. Or we can implement a deep copy ourselves. Because if a 1 element of a container is immutable, the object is still immutable after you copy it, so just copy the pointer. Pointer duplication is sufficient unless you re - assign a value to an element in the container.

For example, after [[array objectAtIndex:0]appendstring: @sd] other objects in the container are not affected.

[[array objectAtIndex:1] and [[deepCopyArray objectAtIndex:0] refer to the same block of memory, but there is no way to change it -- it is immutable. Pointer duplication is sufficient.

So this is not exactly a deep copy, but the official apple document lists it as deep copy and adds a description of the relationship between copy and mutablity.

Or we can implement our own deep copy method.

3. Customize objects

If it's an object that we've defined, then we're going to implement NSCopying,NSMutableCopying ourselves so that we can call copy and mutablecopy. Here's an example:


@interface MyObj : NSObject<NSCopying,NSMutableCopying>
{
NSMutableString *name;
NSString *imutableStr;
int age;
}
@property (nonatomic, retain) NSMutableString *name;
@property (nonatomic, retain) NSString *imutableStr;
@property (nonatomic) int age;
@end
@implementation MyObj
@synthesize name;
@synthesize age;
@synthesize imutableStr;
- (id)init
{
if (self = [super init])
{
self.name = [[NSMutableString alloc]init];
self.imutableStr = [[NSString alloc]init];
age = -1;
}
return self;
}
- (void)dealloc
{
[name release];
[imutableStr release];
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
MyObj *copy = [[[self class] allocWithZone:zone] init];
copy->name = [name copy];
copy->imutableStr = [imutableStr copy];
// copy->name = [name copyWithZone:zone];;
// copy->imutableStr = [name copyWithZone:zone];//
copy->age = age;
return copy;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
MyObj *copy = NSCopyObject(self, 0, zone);
copy->name = [self.name mutableCopy];
copy->age = age;
return copy;
}

So much for the shallow copy and the deep copy (copy and mutableCopy) in iOS, I hope it will be helpful to you!


Related articles: