This mainly focuses on the deep copy of the Collection class, mainly because this problem occurs during work.
If you have any questions, please correct them.
First, we need to have the following premise:
[Array addObject: obj];
In this way, the reference count of obj will increase by 1. If you use remove, the reference count of obj will be reduced by one.
Ios processes the set memory in this way.
Assume that obj is only owned by array:
Id temp = [array objectAtIndex: 0];
[Array removeObjectAtIndex: 0];
If you want to use temp again, an error will occur because obj has been released.
(If you use NSString for testing, note that @ "abc" is a constant :-))
Because the collection class is often used to pass values in the program, a simple retain may not be enough. You need to copy the set content, that is, a deep copy.
Next we will discuss it.
Ios provides the copy and mutablecopy methods. As the name suggests, copy Copies an imutable object, while mutablecopy copies a mutable object. The following are examples.
1. Non-container objects of the system
This refers to objects such as NSString and NSNumber.
NSString * string = @ "origion ";
NSString * stringCopy = [string copy];
NSMutableString * stringMCopy = [string mutableCopy];
[StringMCopy appendString :@"!! "];
Check the memory. We can find that string and stringCopy point to the same memory area (also called apple's weak reference). In this case, the reference count of stringCopy is the same as that of string. StringMCopy is what we call true replication. The system allocates new memory for it, but the Pointer Points to the same string as the string.
Let's 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, mStringCopy is actually an imutable object. Therefore, an error is returned.
For non-container objects in the system, we can think that for an immutable object, copy is Pointer copy (Shortest copy) and mutableCopy is object copy (deep copy ). If you copy a mutable object, it is a deep copy, but the object returned by copy is immutable.
2. system container objects
NSArray, NSDictionary, etc. For the container class itself, the conclusions discussed above are also applicable. We need to discuss the changes of objects in the container after replication.
// Copy returns an immutable object. mutablecopy returns a mutable object.
NSArray * array1 = [NSArray arrayWithObjects: @ "a", @ "B", @ "c", nil];
NSArray * arrayCopy1 = [array1 copy];
// ArrayCopy1 is the same NSArray object as array (pointing to the same object). The elements in array 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 a mutable copy of array1, pointing to an object different from that of array1, but the element 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 replication, while mArrayCopy1 is object replication. mArrayCopy1 can also change the elements in the period: delete or add. But note that all elements in the container are pointer copies.
Next we will 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 are the same object-the same pointer
// Perform a test
NSMutableString * testString = [mArray1 objectAtIndex: 0];
// TestString = @ "1a1"; // This will change the pointer of testString. In fact, the temporary object @ "1a1" is assigned to testString.
[TestString appendString: @ "tail"]; // the first element of the preceding three arrays is changed.
It can be seen that the element object of a container is always pointer replication. If you want to copy element objects as objects, You need to perform deep copy. 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-meaning deep copy, while deepCopyArray is not. For immutable elements in deepCopyArray, it is still a pointer copy. Or we can implement the deep COPY method by ourselves. If a certain element of the container is unchangeable, the object cannot be changed after you copy it. Therefore, you only need to copy the pointer. Pointer replication is sufficient unless you assign a value to the elements in the container. For example, after [[array objectAtIndex: 0] appendstring: @ "sd"], other objects in the container will not be affected. [[Array objectAtIndex: 1] and [[deepCopyArray objectAtIndex: 0] although they point to the same memory, we cannot modify it because it cannot be changed. Therefore, pointer replication is sufficient. Therefore, this is not entirely a deep copy, but apple's official documentation lists it as deep copy and adds a description of the relationship between copy and mutablity, therefore, I would like to explain it here (I have some questions here and I am very grateful for your understanding ).
Or we can implement the deep COPY method by ourselves (omitted ).
3. Custom object
If the object is defined by us, we need to implement NSCopying and NSMutableCopying 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])
{
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;
}
@ End