1. 程式人生 > >Objective-c下的深拷貝、淺拷貝以及NSCopying協議

Objective-c下的深拷貝、淺拷貝以及NSCopying協議

深拷貝&淺拷貝

無論使用什麼語言程式設計我們都必須考慮深拷貝和淺拷貝的問題,只是Objective-c提供了一個實現深拷貝的標準機制而已。所謂淺拷貝其實就是指標的賦值,例如:

NSString* str1 = @"Hello World!";
NSString* str2 = str1;

此時str1和str2同時指向了記憶體中的同一片區域,無論使用哪個指標對該區域進行了改動,使用另一個指標獲取到的內容也會隨之變化。這就是所謂的淺拷貝。而所謂的深拷貝是重新申請一塊區域,重新建立一個物件,同時將原有物件的內容全部複製過來。例如:
NSString* str1 = @"Hello World!"
NSString* str2 = [str1 copy];

此時,無論操作哪個指標對其內容進行修改,另外一個指標所指示的內容不會受到影響。這裡多說一句,呼叫NSString的copy函式複製出來的物件實際和原有物件指向的是同一片區域。但是如果如果對其指向的內容進行修改的話,因為NSString屬於不可改變(immutable)物件,所以系統會重新申請一片空間,寫入修改後的內容返回給該指標。而另外一個指向原來區域的指標不受任何影響。如下:
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString* str = @"hello world";
        NSString* str1 = [str copy];
        NSLog(@"str:%p, str1:%p", str, str1);
        
        str = @"liyazhou";
        NSLog(@"str:%@, str1:%@", str, str1);
        NSLog(@"str:%p, str1:%p", str, str1);

    }
    return 0;
}

得到的結果是:


NSCopying&NSMutableCopying協議

之所以可以在Objective-c下使用copy和mutablecopy函式進行物件的拷貝是因為Objective-c實現了NSCopying和NSMutableCopying協議,這兩個協議規定了對其所屬物件進行復制的具體操作:
@protocol NSCopying

- (id)copyWithZone:(nullable NSZone *)zone;

@end

@protocol NSMutableCopying

- (id)mutableCopyWithZone:(nullable NSZone *)zone;

@end

這兩個協議分別聲明瞭一個方法,而具體的複製操作就在這兩個方法中實現。例如呼叫NSString的copy操作實際就是執行了NSString的copyWithZone函式。

對於常用的型別,這兩個協議都已經實現,所以使用者只需要呼叫copy和mutableCopy方法即可,但是對於自定義的類,要想使用copy方法就必須自己實現該協議。例如:

#import <Foundation/Foundation.h>

@interface Person : NSObject<NSCopying>
{
}

@property (nonatomic, strong) NSString* name;
@property (nonatomic) int age;

-(instancetype)init;
-(id)copyWithZone:(NSZone *)zone;
@end

#import "Person.h"


@implementation Person

-(instancetype)init
{
    self = [super init];
    if(self)
    {
        _name = @"李牙刷兒";
        _age = 25;
        
    }
    
    return  self;
}


-(id)copyWithZone:(NSZone *)zone
{
    Person *p = [[Person allocWithZone:zone]init];
    p.name = self.name;
    p.age = self.age;
    return p;
}




@end