copy|mutablecopy 小述

来源:互联网 发布:编程算法看不懂 编辑:程序博客网 时间:2024/04/29 21:12


copy 和 mutablecopy 到底是怎么回事儿?


原则其实还是这样:所有的设计都是为了功能方便!这两个方法的实现意义大概在两个点:

添加这两个方法,实现了NSString,NSArray 等OC基本数据类型的拷贝操作。

提供一套代理协议模式的设计应用,保留了一套方便的接口,方便用户自定义OC对象拷贝的实现。 



1. 先看Foundation 框架下NSObject.h文件中声明了两个协议:NSCopying NSMutableCopying 


/*************** Basic protocols***************/


@protocol NSCopying


- (id)copyWithZone:(nullableNSZone *)zone;


@end


@protocol NSMutableCopying


- (id)mutableCopyWithZone:(nullableNSZone *)zone;


@end



(1). 其实在真实的开发中,一般来说,真正添加这两个协议来实现拷贝的对象的需求可能不多!而我们最常用的基本OC对象(字符串,数组,集合,字典,NSData ,NSURL,NSIndeSet 等)默认是遵循实现了两个协议或其中一个协议的。看看NSString NSArray头文件就知道了:

@interface NSString :NSObject <NSCopying,NSMutableCopying, NSSecureCoding>

@interface NSArray :NSObject <NSCopying,NSMutableCopying, NSSecureCoding, NSFastEnumeration>

…………

(2). 和NSString、NSArray一样,一个自定义对象实现拷贝功能,所依赖的方法是copy和这mutablecopy,那么久必须—>对应的拷贝对象(NSObject的子类)需要遵循以上两个协议(<NSCopying,NSMutableCopying>)。由此可知,代理模式在OC的语言设计中真的是无处不在呀!

…………

(3). 注意,就算是自定义对象MyObj 遵循了协议,实现协议方法(copyWithZone:| mutableCopyWithZone:)确实要靠自己来写,最后的效果就是以coder的意志做转移的了。但是最好不要这么任性,该copy的还是copy一个给返回,该mutable copy的mutablecopy一份返回,体现这一点可以通过亲自测试,看第二条


2. 以NSStringNSArray为例看看效果, 从而知道copy 和mutablecopy在实际使用中的效果。

       

    NSMutableString *str         = [NSMutableStringstringWithString:@"123"];

        NSString *strCopy            = [strcopy];  ///返回不可变,

        NSMutableString *mustrCopy   = [strmutableCopy];   ///返回可变


        NSLog(@"\n%p->%@, %p->%@, %p->%@",&str,str,&strCopy,strCopy,&mustrCopy,mustrCopy);

//        0x7fff5fbff7d8->123, 0x7fff5fbff7d0->123, 0x7fff5fbff7c8->123


        [mustrCopy appendString:@"z"];

        str =(NSMutableString *)@"321"; /// 注意,和C语言不一样,@出来的东西可是对象,不能实现强转!str将成为不可变。

//        [str appendString:@"a"];  /// 崩溃,原因就是这里(NSMutableString *)不是强转,

        str = [NSMutableStringstringWithFormat:@"321"]; 

        [str appendString:@"a"];


         [[mustrCopy copy]appendString:@"a"];/// 崩溃,[mustrCopy copy]得到的是不可变字符串



        NSMutableArray *muArr       = [NSMutableArrayarrayWithObjects:str,strCopy,mustrCopy,nil];

        NSArray *arrCopy            = [muArrcopy];

        NSMutableArray *muArrCopy   = [arrCopymutableCopy];


        NSLog(@"\n%p->%@, %p->%@, %p->%@",&muArr,muArr[0],&arrCopy,arrCopy[1],&muArrCopy,muArrCopy[2]);

//        0x7fff5fbff7c0->321a, 0x7fff5fbff7b8->123, 0x7fff5fbff7b0->123z




        [muArr[0] appendString:@"b"];

        [muArrCopy[2] appendString:@"y"];



        NSLog(@"\n%p->%@, %p->%@, %p->%@",&muArr,muArr[0],&arrCopy,arrCopy[1],&muArrCopy,muArrCopy[2]);

        NSLog(@"\n%p->%@, %p->%@, %p->%@",&str,str,&strCopy,strCopy,&mustrCopy,mustrCopy);

//        0x7fff5fbff788->321ab, 0x7fff5fbff780->123, 0x7fff5fbff778->123zy

//        0x7fff5fbff7a0->321ab, 0x7fff5fbff798->123, 0x7fff5fbff790->123zy


        strCopy     = @"UHB";

        [mustrCopy  appendString:@"YGV"];


        NSLog(@"\n%p->%@, %p->%@, %p->%@",&muArr,muArr[0],&arrCopy,arrCopy[1],&muArrCopy,muArrCopy[2]);

        NSLog(@"\n%p->%@, %p->%@, %p->%@",&str,str,&strCopy,strCopy,&mustrCopy,mustrCopy);


//        0x7fff5fbff788->321ab, 0x7fff5fbff780->123, 0x7fff5fbff778->123zyYGV

//        0x7fff5fbff7a0->321ab, 0x7fff5fbff798->UHB, 0x7fff5fbff790->123zyYGV

这个地方可以看出,数组中的可变字符串其实并没有copy新建,而是指向原始可变字符串。

(1) . 只看copy 和 mutablecopy,就我个人目前的意识来看,在OC基本对象数据类型中比较有意义,毕竟一切都是为了方便使用嘛! 对于这些OC基本类型,对于存在mutable和imutable的, copy 和mutablecopy的意义就特别明显了。不过其中存在一些注意点:

a. copy 和 mutablecopy都是创建了一个新的对象,copy的不可变,mutablecopy的可变。

b. 对于数组,数组中的成员如果是可变的,则是原有对象指针拷贝,如果是不可变的,则是内容拷贝。字典同理

c. copy 和 mutablecopy 如果是使用于OC的基本对象数据类型的时候,规律是恒定的。基本如上,可以将NSString理解为最原子的对象。


(2). 上面是讨论OC的基本对象数据类型,线面 新建一个 Person类,看看自定义的对象如何使用 copy 和 mutablecopy 。


@interface Person :NSObject<NSCopying,NSMutableCopying>


@property (nonatomic,strong) NSString  *name;

@property (nonatomic,assign) NSInteger age;

@property (nonatomic,strong) NSString  *title;


@end


@implementation Person


- (NSString *)description

{

    return [NSStringstringWithFormat:@"name: %@, age: %ld, title: %@",_name,(long)_age,_title];

}


- (id)copyWithZone:(NSZone *)zone

{

    Person *person = [Personnew];

    person.age      =self.age;

    person.name     =self.name;

    person.title    =self.title;

    return person;

}


- (id)mutableCopyWithZone:(NSZone *)zone

{

    // mutablecopy 的处理方法,全由意志处理并不好!

    // zone 这是一个表示管理内存的标示,且不管它

    returnself;

}


@end





        Person *_person = [[Personalloc] init];

        Person *_personCopy = _person;

        [_person setValuesForKeysWithDictionary:@{

                                                 @"name"  :  @"小名",

                                                 @"age"   :   @26,

                                                 @"title" :  @"CEO"

                                                 }];

        NSLog(@"\n %p -> %@ | %p -> %@",&_person, _person, &_personCopy, _personCopy);

//        0x7fff5fbff770 -> name: 小名, age: 26, title: CEO | 0x7fff5fbff768 -> name:小名, age: 26, title: CEO


        _personCopy = [_person copy];///想要不崩溃,需遵循NSCoping协议,并实现协议方法  copyWithZone

        _personCopy.name =@"小明";


        NSLog(@"\n %p -> %@ | %p -> %@",&_person, _person, &_personCopy, _personCopy);

//        0x7fff5fbff770 -> name: 小名, age: 26, title: CEO | 0x7fff5fbff768 -> name:小明, age: 26, title: CEO


        _person.name =@"小张";


        _personCopy = [_person mutableCopy];


        NSLog(@"\n %p -> %@ | %p -> %@",&_person, _person, &_personCopy, _personCopy);

//        0x7fff5fbff770 -> name: 小张, age: 26, title: CEO | 0x7fff5fbff768 -> name:小张, age: 26, title: CEO




_结语:

copy mutablecopy是两个写在 NSObject中的方法,是利用协议代理方法保留一套接口,OC 实现了(字符串,数组,集合,字典,NSData ,NSURL,NSIndeSet )这些基本OC对象数据类型的接口方法,对于其他的自定义OC对象,要使用copy 和mutablecopy方法需要手动添加协议(<NSCopying,NSMutableCopying>),并实现两个协议的required方法(mutableCopyWithZone:  | copyWithZone:)。

协议方法中必定需要返回一个 对象类型,具体怎么处理权限上就是任coder的意志决定,然而此处最好准许OC基本对象数据类型的规律。






0 0