IOS — Copy

Copy程序員

主要內容:less

  • copy的基本使用
  • 自定義對象的copy屬性
  • 支持copy的自定義對象

 

 

1. copy的基本使用優化

♠ copy的效果:atom

  對源對象進行copy,創建出新的副本,彼此修改互不干擾!spa

♠ OC中有兩種copy方式設計

  1> copy指針

    若是對象有可變/不可變之分,copy只能copy出不可變版本,若是沒有此區分,copy方法就是創建一個副本。code

  2> mutableCopy對象

    創建對象的可變副本(僅僅是當對象有可變和不可變版本時才須要是要本方法)blog

 

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self copyDemo1];
    NSLog(@"------------------");
    [self copyDemo2];
}

- (void)copyDemo1{
    NSString *str1 = @"copy1";
    NSLog(@"%@ %p",[str1 class],str1);
    // copy   => 不可變  不產生新對象 至關於引用計數器+1
    id  obj = [str1 copy];
    NSLog(@"%@ %p",[obj class],obj);
    // mutableCopy  => 可變  產生新對象
    id obj2 = [str1 mutableCopy];
    NSLog(@"%@ %p",[obj2 class],obj2);
}

- (void)copyDemo2{
    NSMutableString *str2 = [NSMutableString stringWithString:@"copy2"];
    NSLog(@"%@ %p",[str2 class],str2);
    // copy   => 不可變 產生新對象
    id obj1 = [str2 copy];
    NSLog(@"%@ %p",[obj1 class],obj1);
    // mutableCopy  => 可變,產生新對象
    id obj2 = [str2 mutableCopy];
    NSLog(@"%@ %p",[obj2 class],obj2);
    
}
@end

♠ 小結:

  可變    ---> 不可變

  可變    ---> 可變

  不可變 ---> 可變                      以上3種都會產生新的對象(深拷貝)

 

  不可變 ---> 不可變                   不會產生新對象,僅僅是對計數器+1(淺拷貝)

 


2. 自定義對象的copy屬性

♠ 當一個對象的NSString類型屬性使用strong 修飾

@property (nonatomic,strong) NSString *name;

 若是對該屬性作以下設置

person *p = [[person alloc]init];
    
    NSMutableString *str = [NSMutableString stringWithString:@"aaaa"];
    
    p.name = str;
    
    NSLog(@"%@",[p.name class]);   // 輸出結果:__NSCFString
    
    [str setString:@"bbbb"];
    
    NSLog(@"%@",[p.name class]);   // 輸出結果:__NSCFString

從打印輸出能夠發現:

p.name屬性的類型已經變爲NSMutableString類型,而與咱們當初定義的類型不一致,爲何?

  由於一個對象的準確類型是在給改對象「分配內存空間」的時候制定的類型,而程序員指定屬性爲某對象的類型以後就能夠具備該對象的方法,而可否運行成功取決於該屬性的實際類型,若是使用了實際類型不存在的方法,將會報"unrecognized selector send to instance"

例如:

    id aa  = [[NSObject alloc]init];
    
    NSString *string = aa;
    
    NSLog(@"%zd",string.length);

  此代碼塊中,定義了NSString類型的變量,試圖指向了NSObject的對象,當調用NSString的length方法時,編譯能夠經過,可是因爲string的實際類型是NSObject類型,並不存在該方法,全部會報方法不存在錯誤:

unrecognized selector sent to instance 0x7f9628c8b7f0'

 

發現問題: 

  當咱們使用strong修飾成員屬性時,將會有多個指針指向相同的對象,並可對其進行操做,而在程序設計過程當中,有些時候咱們的操做並不但願影響源數據,此時可能就須要改變變量的修飾爲copy

 

♠ 面向對象程序開發中,有一個很是重要的原則

開閉原則:

  - 開:對內開放,想怎麼改,就怎麼改

  - 閉:對外封閉,只能用,不能改

定義成copy的屬性,在設置時會默認進行一次copy操做;

  -> 對可變屬性進行copy ———— 新建副本

  -> 對不可變屬性進行copy ———— 不會建立新的對象,只是計數器+1,跟strong類型一致的。

使用注意:

  對於有可變與不可變之分類型的屬性而言,因爲copy操做獲得的將是不可變類型,全部對於可變類型的屬性,不該該使用copy去修飾。


 

3. 支持copy的自定義對象

先來看程序,有自定義類,有兩個成員屬性

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

控制器中實例化對象,並嘗試使用copy

person *p1 = [[person alloc] init];
    p1.name = @"aaa";
    p1.age  = 12;
    
    person *p2 = [p1 copy];
    p2.name = @"bbb";
    p2.age  = 14;

運行可發現:

-[person copyWithZone:] 系統將提示沒有實現copyWithZone方法;

 

那麼問題來了,copyWithZone:與copy方法有什麼關係?

蘋果官方文檔中描述:

Returns the object returned by copyWithZone:,

This is a convenience method for classes that adopt the NSCopyingprotocol. An exception is raised if there is no implementation for copyWithZone:.

NSObject does not itself support the NSCopyingprotocol. Subclasses must support the protocol and implement the copyWithZone: method. A subclass version of the copyWithZone: method should send the message to super first, to incorporate its implementation, unless the subclass descends directly from NSObject.

咱們能夠從中獲得一些信息:
1> copy 是 copyWithZone的簡化形式,若是沒有實現copyWithZone方法而調用copy會出現異常;

2> NSObject 類自己並無遵照NSCopying協議,子類想要使用copy方法,必須遵照協議,而且實現copyWithZone方法;

3> 子類實現copyWithZone:方法必須先調用父類的copyWithZone,除非子類直接繼承於NSObject

也就是說若要是的咱們自定義類可以拷貝,有兩個條件:

  * 類遵照NSCopying協議

  * 類實現copyWithZone:方法

      Zone: 分配對象是須要內存空間的,若是指定了zone,就能夠指定新對象的內存空間,可是zone是一個很是古老的技術,爲避免在堆中出現碎片而使用的,現在已幾乎不用。

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

self.class 的緣由:

  1> copyWithZone: 是一個對象方法,self.class 得到類對象

  2> 保證建立的對象都是person類或者子類對象

若是父類也實現了copyWithZone:方法,必須調用父類copyWithZone:方法。

 


 4. copy修飾的結構體

  問題:block類型的變量爲何要用copy修飾?

    由於在ARC下,編譯器底層對block作了一些優化,能夠防止出現內存泄露,若是使用了strong,至關於強引用了一個棧區變量,從內存管理的角度而言,程序員須要管理的僅僅是堆區,全部在對block類型變量進行復制時要使用copy,對值進行一次copy操做,將其copy到堆區。

相關文章
相關標籤/搜索