1. 程式人生 > >ios-關於深拷貝和淺拷貝和屬性中的copy和strong的區別

ios-關於深拷貝和淺拷貝和屬性中的copy和strong的區別

深拷貝就是把內容拷貝一份產生一份新的物件,新物件計數器為1,源物件計數器不變。

而淺拷貝是指標拷貝,把地址給你,你和我指向同一個物件,源物件計數器加一,源物件和副本的計數器相同。

我們知道在OC中的拷貝函式有copy和mutablecopy,只要你呼叫了copy不管是NSString, NSDictionary還是NSArray還是NSMutableString還是NSMutableDictionary,還是NSMutableArray都是copy出來是不可變的副本。

當你呼叫mutablecopy產生的都是可變的副本。可變物件和不可變物件進行mutablecopy都是產生了一個新的物件,計數器為1,原來的物件計數器不變。而如果是copy而且是不可變物件進行copy的話則是淺拷貝沒有產生一個新的物件相當於retain操作了,因為OC設定copy語法本身就是為了改變副本而不去影響源物件,所以為了效能著想既然copy出來的都不可變了,自然也就不會產生一個新的物件了。

可變物件進行copy就是深拷貝因為可變物件變成了不可變物件了,結構上發生了改變。總結來說就是隻有不可變物件呼叫copy為淺拷貝其他都是深拷貝。

@property屬性的copy代表的是set方法會release舊物件,copy一個產生新物件其實就是把retain的set方法中最後的retain改成了copy。所以其實就是這個意思.此處title是@property(copy,nonatomic)NSString * title;在manger這個類中

NSString *str1=[NSString stringWithFormat:@"hahha"];
        Manger *manger1=[[Manger alloc]init];
        manger1.title=str1;
        NSLog(@"%i",manger1.title==str1);//輸出是1,是淺拷貝
 NSMutableString *str1=[NSMutableString stringWithFormat:@"hahha"];
        Manger *manger1=[[Manger alloc]init];
        manger1.title=str1;
        NSLog(@"%i",manger1.title==str1);//輸出為0,是深拷貝

NSString一般都用copy,不過還是得看需求。

如果我們想讓一個類的物件進行拷貝操作就要讓這個類要實現NSCopying或者NSMutableCopying協議。然後我們還要在類的.m檔案中實現-(id)copyWithZone:(NSZone *)zone方法,其中zone指向新的一塊儲存空間,是系統已經給我們分配的記憶體。具體實現如下。

-(id)copyWithZone:(NSZone *)zone
{
 Manger *copy=[[[self class] allocWithZone:zone]init];//這裡就是用系統自己給分配的記憶體,此處最好用self class 來代替類名
 copy.title=self.title;
 return copy
}

總結:可變物件的copy和mutableCopy方法都是深拷貝,而且都是是單層拷貝也就是說我有個陣列a和陣列b,我讓陣列b = [a copy]或者 b = [a mutableCpoy],雖然b的地址和a的地址不同,但是其裡面的陣列元素的地址和原數組裡面的物件的地址還是相同的,也就是說陣列內容還是指向原數組裡面的元素的。

不可變物件的copy方法是淺拷貝,mutableCopy的方法是深拷貝

copy方法返回的物件都是不可變物件

如果我們想實現陣列中的物件也可以進行深拷貝的話,我們可以這麼做,其實就是利用了歸檔的方式

- (void) deplyFullCopy
{
    NSMutableArray *arrayM1 = [[NSMutableArray alloc] init];
    
    NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"哈哈"];
    NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"呵呵"];
    
    [arrayM1 addObject:mstr1];
    [arrayM1 addObject:mstr2];
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arrayM1];
    NSArray *arrayM2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];
    
    
    NSLog(@"marry1:%p --- %@ \r\n",arrayM1,arrayM1);
    NSLog(@"marry2:%p --- %@ \r\n",arrayM2,arrayM2);
    NSLog(@"陣列元素地址:value1:%p --- value2:%p \r\n",arrayM1[0],arrayM1[1]);
    NSLog(@"陣列元素地址:value1:%p --- value2:%p \r\n",arrayM2[0],arrayM2[1]);
}