美文网首页YLiOSiOS Developer
NSString copy or strong?

NSString copy or strong?

作者: JiandanDream | 来源:发表于2016-01-13 11:02 被阅读452次

    结论

    • 对于copy修饰的属性来说,若赋值源是NSString、NSArray、NSURLRequest三者其中之一,复制时是shallow copy(浅复制),即地址相同,类型相同。
    • 一般情况下,NSString使用copy修饰。即:
    @property (nonatomic, copy) NSString *string;
    

    解释说明

    结论1

    首先,需要知道

    copy和strong对应的所有权修饰符都是 __strong。
    strong修饰的属性,赋值后,地址相同,类型相同。
    copy修饰的属性,赋值时,通过 NSCopying 接口的 copyWithZone: 方法复制赋值源所生成的对象,赋值后,地址不一定相同,类型不一定相同。
    

    而复制分为shallow copy与deep copy,区别如下:

    shallow copy 即浅复制,没有产生新对象,指针指向原来对象。
    deep copy 即深复制,产生新对象。
    

    接着,Show the code

    String相关属性

    @property (nonatomic, strong) NSString *strongString;               /**<strong string*/
    @property (nonatomic, strong) NSMutableString *mStrongString;       /**<strong mutable string*/
    @property (nonatomic, copy) NSString *cString;                      /**<copy string*/
    @property (nonatomic, copy) NSMutableString *mCopyString;           /**<copy mutable string*/
    

    对String的测试

    - (void)stringTest {
        //来源是NSString
        NSString *string = @"string";
        NSLog(@"address: %p | class: %@ of string",string,[string class]);
        self.strongString = string;
        self.cString = string;
        self.mStrongString = string;
        self.mCopyString = string;
        [self printStringInfo];
    
        NSLog(@"\n");
    
        //来源是NSMutableString
        NSMutableString *mutableString = [NSMutableString stringWithString:@"mutable string"];
        NSLog(@"address: %p | class: %@ of mutable string",mutableString,[mutableString class]);
        self.strongString = mutableString;
        self.cString = mutableString;
        self.mStrongString = mutableString;
        self.mCopyString = mutableString;
        [self printStringInfo];
    }
    
    - (void)printStringInfo {
        NSLog(@"address: %p | class: %@ of strong string",self.strongString,[self.strongString class]);
        NSLog(@"address: %p | class: %@ of copy string",self.cString,[self.cString class]);
        NSLog(@"address: %p | class: %@ of strong mutable string",self.mStrongString,[self.mStrongString class]);
        NSLog(@"address: %p | class: %@ of copy mutable string",self.mCopyString,[self.mCopyString class]);
    }
    

    (注:以上是只有部分代码,想了解更多,请查看文章底部的源代码)

    然后,分别打印来源是NSString、NSArray、NSURLRequest的运行结果:

    来源是NSString 来源是NSArray 来源是NSURLRequest
    对比以上3张图中的地址及类型,可知:
    来源是NSString、NSArray、NSURLRequest三者之一的,使用strong或copy修饰的,赋值结果都是一样的,可证明结论1:
    对于copy修饰的属性来说,若赋值源是NSString、NSArray、NSURLRequest三者其中之一,复制时是shadow copy(浅复制),即地址相同,类型相同。
    结论2

    分别打印来源是NSMutableString、NSMutableArray、NSMutableNSURLRequest的结果:


    来源是NSMutableString 来源是NSMutableArray 来源是NSMutableNSURLRequest

    对比以上3张图中的地址及类型,可知:
    来源若是NSMutableString,NSMutableArray,NSMutableURLRequest之一

    • 使用strong修饰的,赋值后,地址相同,类型也相同。
    • 使用copy修饰的,会复制赋值源所生成的对象,复制后,地址不同,而来源是NSMutableArray的,甚至连类型也不同(__NSArrayI__NSArrayM),说明复制时都是deep copy(深复制)。

    (据了解,copy除了复制NSString、NSArray、NSURLRequest外,其他都是deep copy。)(未知真实性)

    也就是说:
    如果来源是NSString,使用copy或strong没有区别。
    如果来源是NSMutableString,NSString对象会因其改变而改变。若使用copy,因为是深复制,产生了一个新的对象,就可以避免以上情况。

    而一般使用NSString变量时,并不希望它可变,Objective-C的类型确定又是在运行时才决定的,那么赋值时,很可能会搞错赋值源的类型:NSMutableString误当作NSString,这样也许会带来不可预知的问题,而且此类问题一般不易察觉,所以可说明结论2:
    一般情况下,NSString使用copy修饰。
    当然,具体情况,具体分析,使用strong也无可厚非。

    附录:剩余的主要代码

    Array相关属性

    @property (nonatomic, strong) NSArray *strongArray;                 /**<strong array*/
    @property (nonatomic, strong) NSMutableArray *mStrongArray;         /**<strong mutable array*/
    @property (nonatomic, copy) NSArray *cArray;                        /**<copy array*/
    @property (nonatomic, copy) NSMutableArray *mCopyArray;             /**<copy mutable array*/
    

    URL Request相关属性

    @property (nonatomic, strong) NSURLRequest *strongRequest;          /**<strong request*/
    @property (nonatomic, strong) NSMutableURLRequest *mStrongRequest;  /**<strong mutalbe request*/
    @property (nonatomic, copy) NSURLRequest *cRequest;                 /**<copy request*/
    @property (nonatomic, copy) NSMutableURLRequest *mCopyRequest;      /**<copy mutable request*/
    

    对Array的测试

    - (void)arrayTest {
        //来源是NSArray
        NSArray *array = @[ @"item1",@"item2"];
        NSLog(@"address: %p | class: %@ of array",array,[array class]);
        self.strongArray = array;
        self.cArray = array;
        self.mStrongArray = array;
        self.mCopyArray = array;
        [self printArrayInfo];
        
        NSLog(@"\n");
        
        //来源是NSMutableArray
        NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
        NSLog(@"address: %p | class: %@ of mutable array",mutableArray,[mutableArray class]);
        self.strongArray = mutableArray;
        self.cArray = mutableArray;
        self.mStrongArray = mutableArray;
        self.mCopyArray = mutableArray;
        [self printArrayInfo];
    }
    
    - (void)printArrayInfo {
        NSLog(@"address: %p | class: %@ of strong array",self.strongArray,[self.strongArray class]);
        NSLog(@"address: %p | class: %@ of copy array",self.cArray,[self.cArray class]);
        NSLog(@"address: %p | class: %@ of strong mutable array",self.mStrongArray,[self.mStrongArray class]);
        NSLog(@"address: %p | class: %@ of copy mutable array",self.mCopyArray,[self.mCopyArray class]);
    }
    

    对URL Request的测试

    - (void)urlRequestTest {
        //来源是NSURLRequest
        NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
        
        NSLog(@"address: %p | class: %@ of url request",urlRequest,[urlRequest class]);
        self.strongRequest = urlRequest;
        self.cRequest = urlRequest;
        self.mStrongRequest = urlRequest;
        self.mCopyRequest = urlRequest;
        [self printRequestInfo];
        
        NSLog(@"\n");
        
        //来源是NSMutableURLRequest
        NSMutableURLRequest *mutableURLRequest = [NSMutableURLRequest requestWithURL:url];
        NSLog(@"address: %p | class: %@ of mutable request",mutableURLRequest,[mutableURLRequest class]);
        self.strongRequest = mutableURLRequest;
        self.cRequest = mutableURLRequest;
        self.mStrongRequest = mutableURLRequest;
        self.mCopyRequest = mutableURLRequest;
        [self printRequestInfo];
    }
    
    - (void)printRequestInfo {
        NSLog(@"address: %p | class: %@ of strong request",self.strongRequest,[self.strongRequest class]);
        NSLog(@"address: %p | class: %@ of copy request",self.cRequest,[self.cRequest class]);
        NSLog(@"address: %p | class: %@ of strong mutable equest",self.mStrongRequest,[self.mStrongRequest class]);
        NSLog(@"address: %p | class: %@ of copy mutable request",self.mCopyRequest,[self.mCopyRequest class]);
    }
    

    相关文章

      网友评论

      • ShawnFoo:建议遵循不可变性原则, 任何遵循NSCopying协议的类实例使用copy修饰, 该实例变量的默认setter会对传入的值进行[var copy]处理
        比如现分别有 用copy和strong修饰的属性
        @property (copy, nonatomic) NSString *copyName;
        @property (strong, nonatomic) NSString *strongName;

        通过setter分别对其赋值一个NSMutableString对象 mutableName时
        self.copyName = mutableStr --> 该setter方法 内会对 [mutableName copy]操作
        self.strongName = mutableStr --> 而该setter 就直接将一个NSMutableString对象的地址赋给了strongName指针变量

        所以当 mutableName的内容 改变时 , self.strongName也会发生变化, 而copyName就不会. 这种bug找起来会很蛋疼的
        JiandanDream:@ShawnFoo 谢谢提醒!
      • 我真不会修电脑:是不是可以理解为copy修饰,源变我不变,strong修饰,源变我也变。
        我真不会修电脑:@JiandanDream :smile::smile:受教了 多谢
        JiandanDream:@我真不会修电脑 改成这样吧:copy修饰,来源除了NSString,NSArray,NSRequest外,源变我不变。
      • 小赢一场:很好
        JiandanDream:@a79860bfcaf5 谢谢! :blush:

      本文标题:NSString copy or strong?

      本文链接:https://www.haomeiwen.com/subject/rofckttx.html