ios provides copy and mutablecopy methods. As the name suggests, copy means copying an mutable object, and mutablecopy means copying a mutable object.
The difference between copy and retain:
copy is to create a new object, retain is to create a pointer, and the reference object count is to add 1. The Copy property indicates that the content of the two objects is the same, and the new object retain is 1, which has nothing to do with the reference count of the old object, and the old object has not changed. copy reduces the object's dependence on the context.
The retain attribute means that the two objects have the same address (create a pointer and copy of the pointer), and the content is of course the same. The retain value of this object +1 means that retain is the pointer copy and copy is the content copy.
Of course, not all objects in iOS support copy and mutableCopy. Classes that comply with the NSCoping protocol can send copy messages, and classes that comply with the NSMutableCopying protocol can send mutableCopy messages. If a copy or mutableCopy is sent without complying with the two-part appeal agreement, an exception will occur. However, the default ios class does not comply with these two protocols. If you want to customize copy, you must comply with NSCoping and implement the copyWithZone: method. If you want to customize mutableCopy, you must comply with NSMutableCopying and implement the mutableCopyWithZone: method.
First of all, we need to have this premise:
[array addObject:obj];
This way the reference count of obj will be increased by 1, and if remove is used, the reference count of obj will be decreased by one.
This is how ios handles the memory of the collection.
Then, assume obj is only owned by array:
id temp = [array objectAtIndex:0];
[array removeObjectAtIndex:0];
If you want to use temp again, you will make an error because obj has been released at this time.
(A reminder, if you use NSString for testing, please note that @"abc" is a constant :-) )
Since you often encounter the value of the collection class in a program, a simple retain may not be enough, and a copy of the collection content is required, that is, a deep copy.
Let’s discuss it below.
Ios provides copy and mutablecopy methods. As the name suggests, copy means copying an mutable object, and mutablecopy means copying a mutable object.
Here are a few examples to illustrate.
1. System non-container class object
Here we refer to objects such as NSString, NSNumber, etc.
NSString *string = @"origion"; NSString *stringCopy = [string copy]; NSMutableString *stringMCopy = [string mutableCopy]; [stringMCopy appendString:@"!!"];
When looking at the memory, you can find that string and stringCopy point to the same memory area (also known as apple weak reference weak reference). At this time, the reference count of stringCopy is the same as that of string. stringMCpy is what we call a true copy, and the system allocates new memory to it, but the string pointed to by the pointer is still the same as string refers to.
Let’s take a look at the following 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:@"!!"];
The memory allocated by the above four NSString objects is different. However, for mStringCopy, it is actually an imutable object, so the above will report an error.
For non-container-like objects of the system, we can think that if copying an immutable object, copy is pointer copy (shallow copy) and mutableCopy is object copy (deep copy). If you copy a mutable object, it is all deep copy, but the object returned by copy is immutable.
2. System container class object
Refers to NSArray, NSDictionary, etc. For the container class itself, the conclusion discussed above is also applicable. What needs to be discussed is the changes in the objects in the container after copying.
//copy returns immutable object, mutablecopy returns mutable objectNSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil]; NSArray *arrayCopy1 = [array1 copy]; //arrayCopy1 is the same NSArray object as array (points to the same object), including elements in array also point to the same pointerNSLog(@"array1 retain count: %d",[array1 retainCount]); NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]); NSMutableArray *mArrayCopy1 = [array1 mutableCopy]; //mArrayCopy1 is a mutable copy of array1. The object pointed to is different from array1, but the element in it and the element in array1 point to the same object. mArrayCopy1 can also modify its own object[mArrayCopy1 addObject:@"de"]; [mArrayCopy1 removeObjectAtIndex:0];
array1 and arrayCopy1 are pointer copying, while mArrayCopy1 is object copying, mArrayCopy1 can also change elements during the period: delete or add. But note that the contents of the elements in the container are all pointers.
Let's use another example to test it.
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 point to different objects, but the elements in them are the same object-the same pointer//Try the testNSMutableString *testString = [mArray1 objectAtIndex:0]; //testString = @"1a1";//This will change the pointer of the testString, and in fact, assigning the temporary object @"1a1" to the testString[testString appendString:@" tail"];//In this way, the first elements of the above three arrays have been changed
It can be seen that for a container, its element object is always pointer copying. If the element object is also object copying, deep copying is required.
/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/ 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 deep copy in the full sense, while deepCopyArray is not, and it is still a pointer copy for immutable elements within deepCopyArray. Or we can implement deep copy methods ourselves. Because if an element of the container is immutable, the object cannot be changed after you copy it, so you only need to copy the pointer. Unless you reassign the elements in the container, pointer copying is enough.
For example, other objects in the container after [[array objectAtIndex:0]appendstring:@"sd"] will not be affected.
Although [[array objectAtIndex:1] and [[deepCopyArray objectAtIndex:0] point to the same piece of memory, there is no way to modify it - because it is unchangeable. So pointer copying is enough.
So this is not a deep copy in the complete sense, but Apple's official documentation lists it as deep copy and adds a description of the relationship between copy and mutable, so I'll explain it here (I'm still a little confused here, I'll have some advice on it).
Or we can implement deep copy ourselves (omitted).
3. Custom Objects
If it is an object we define, then we need to implement NSCoping and NSMutableCopying ourselves so that we can call copy and mutablecopy. For 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]) { = [[NSMutableString alloc]init]; = [[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 = [ mutableCopy]; copy->age = age; return copy; }
I will introduce so much to you about shallow and deep copies in iOS (copy and mutableCopy) and I hope it will be helpful to you!