程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Objective-C 淺析Copy語法

Objective-C 淺析Copy語法

編輯:關於C語言

在OC語法中,提供了Copy語法(Copy + MutableCopy)用於對象的拷貝。其中很容易混淆的是淺拷貝和深拷貝。

所謂淺拷貝,即是地址拷貝,並不產生新的對象,而是對原對象的引用計數值加1。而深拷貝,即是對象拷貝,產生新的對象副本,計數器為1。

下面通過一個例子來分析一下這個比較容易亂的Copy:

一、對於NSString/NSMutableString; NSArray/NSMutableArray... 這OC提供的類對象:

以NSString/NSMutableString為例:

對於copy,返回的一定是不可變類型;而mutableCopy,返回的一定是可變類型。

①對於 mutableCopy ,一定是深拷貝。

//對於 mutableCopy,都是深拷貝:對象的拷貝,產生新的對象
void strMutableCopy(){
    
    NSString *str=[[NSString alloc]initWithFormat:@"abcd"];
//    NSMutableString *str = [[NSMutableString alloc] initWithFormat:@"abcd"];
    
    //產生了一個新的對象 計數器為1 源對象的計數器不變
    NSMutableString *str2=[str mutableCopy];
//    NSString *str2 = [str mutableCopy];
    
    //輸出二者的地址,二者的地址是不同的
    NSLog(@"str --> %p",str);
    NSLog(@"str2 --> %p",str2);
}

②對於 copy:

如果是 NSString ---> NSString;則是淺拷貝;如果是 NSMutableString ---> NSString;則是 深拷貝

如果是 NSString 、NSMutableString ---> NSMutableString;則是深拷貝

注:只有一種情況下是發生淺拷貝:不可變對象 復制到 不可變對象。

//淺拷貝:指針拷貝 不會產生新的對象,源對象計數器加1
void strCopy(){
    
    NSString *str=[[NSString alloc]initWithFormat:@"abcd"];
    //因為NSString對象本身就不可變,所以並沒產生新的對象,而是返回對象本身,會做一次retain操作,所以源對象也會retain
    NSString *str2=[str copy];
        
    //輸出二者的地址,二者的地址是相同的
    NSLog(@"str --> %p",str);
    NSLog(@"str2 --> %p",str2);
}

除了以上這種情形外,其他都是深拷貝。

例如:

//深拷貝
void mutableStrCopy(){
    
    NSMutableString *str=[[NSMutableString alloc]initWithFormat:@"abcd"];
    
    //會產生一個新的對象計數器1
    NSString *str2=[str copy];
    
    //輸出二者的地址,二者的地址是不同的
    NSLog(@"str --> %p",str);
    NSLog(@"str2 --> %p",str2);
}

二、對於自定義對象的Copy:該類必須實現NSCopying協議,重寫 copyWithZone 方法。

同理,對於自定義對象的mutableCopy:必須實現 NSMutableCopying 協議,重寫 mutableCopyWithZone 方法。

在NSCopying協議中,其實只有一個協議方法:

@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end


在NSMutableCopying協議:

@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end

下面給出一個例子:

#import 

@interface Person : NSObject

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

-(instancetype)initWithAge:(int)age withName:(NSString*)name;

@end

#import "Person.h"

@implementation Person

-(instancetype)initWithAge:(int)age withName:(NSString*)name{
    self = [super init];
    if (self) {
        self.age = age;
        self.name = name;
    }
    return self;
}

-(id)copyWithZone:(NSZone *)zone{
    Person* person = [[[self class] allocWithZone:zone] initWithAge:self.age withName:self.name];
    return person;
}

@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        
        Person *p1 = [[Person alloc] initWithAge:20 withName:@"Jack"];
        Person *p2 = [p1 copy];
        
        //輸出兩個 Person 對象的地址,二者是不同的
        NSLog(@"p1 --> %p",p1);
        NSLog(@"p2 --> %p",p2);
    }
    return 0;
}

加入對於某些自定義對象是不可變的,那麼如何辦呢?
-(id)copyWithZone:(NSZone *)zone{
    return self;
}
這樣,輸出的兩個對象的地址就是相同的了。


下面了解一下關於如果某一個自定義類繼承了 這個Person類的情況。

如果某一個子類繼承了實現了NSCopying協議的基類,那麼該子類也是會自動繼承這個協議的方法。但是需要自己重新實現。

例如:有一個Student子類繼承了這個Person類:

#import 
#import "Person.h"
@interface Student : Person

@property(nonatomic,copy)NSString *school;

-(instancetype)initWithAge:(int)age withName:(NSString *)name WithSchool:(NSString*)school;

@end


#import "Student.h"

@implementation Student

-(instancetype)initWithAge:(int)age withName:(NSString *)name WithSchool:(NSString*)school{
    self = [super initWithAge:age withName:name];
    if (self) {
        self.school = school;
    }
    return self;
}

-(id)copyWithZone:(NSZone *)zone{
    Student *student = [super copyWithZone:zone];
    student.school = self.school;
    return student;
}

@end

注意其中copyWithZone方法的實現。



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved