copy retain assign的差别在于对象属性的set方法

  • NSString 与 NSMutableString

NSString是不可变字符串对象,这句话的意思,结合代码:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        NSString *str = @"Shaw";
        NSString *str1 = @"Root";   // NSString *str1的意思是str1指向的@"Root"对象是不可变的,但str1是可以改变指向的。
        NSLog(@"str = %@, str1 = %@",str,str1);
        NSLog(@"str:%p, str1:%p",str,str1);
        str = [str stringByAppendingString:@"andRoot"];  // 打印可以看到str地址变了,因为原地址下的对象是不可变的。
        NSLog(@"str:%p, str1:%p",str,str1);
        str1 = str;  // 使str1指向str对象
        NSLog(@"str = %@, str1 = %@",str,str1);
        NSLog(@"str:%p, str1:%p",str,str1);

    }
    ;
}// 输出结果
-- :::] str = Shaw, str1 = Root
-- :::] str:0x100001050, str1:0x100001070
-- :::] str:0x1001026b0, str1:0x100001070
-- :::] str = ShawandRoot, str1 = ShawandRoot
-- :::] str:0x1001026b0, str1:0x1001026b0
Program ended with exit code: 

同理,NSMutableString就是可变字符串对象。

stringByAppendingString:方法的定义为:- (NSString *)stringByAppendingString:(NSString *)aString;

        NSMutableString *mStr = [NSMutableString stringWithString:@"Shaw"];
        NSLog(@"%@ %p",mStr,mStr);
        [mStr appendString:@"andRoot"]; //  可以看到输出地址为同一个,即对当前对象做了改变。
        NSLog(@"%@ %p",mStr,mStr);

// 输出结果
-- :::] Shaw 0x100203470
-- :::] ShawandRoot 0x100203470
Program ended with exit code: 

如果用NSMutableString对象调用stringByAppendingString:方法会出现警告"Incompatible pointer types assigning NSMutableString to NSString"


  • mutableCopy(遵从NSMutableCopying协议的对象可用) 与 copy (遵从NSCopying协议的对象可用)

前者返回的对象是可变的, 后者返回的是不可变的

所以用copy方法返回的字符串是NSString *, mutableCopy方法返回的字符串是NSMutableString *.

有如下的结果:

复制不可变对象时

1. copy是浅复制,即指针复制,两个指针都指向那块空间

2. mutableCopy是深复制,即新开辟一块空间,将对象复制过去

复制可变对象时

mutableCopy与copy都是深复制,但copy返回的对象不可变

下面可以用代码一一验证:

 //      复制不可变对象
         NSString *str = @"Shaw";

         NSString *strCopy = [str copy];    // 相当于 [str retain]
         NSMutableString *strMCopy = [str mutableCopy];

         NSLog(@"%@:%p %@:%p %@:%p",str,str,strCopy,strCopy,strMCopy,strMCopy);
         strCopy = [str stringByAppendingString:@"andRoot"];           strMCopy = [strMCopy stringByAppendingString:@"andRoot"];
         NSLog(@"%@:%p %@:%p %@:%p",str,str,strCopy,strCopy,strMCopy,strMCopy);

 //  输出结果
 -- :::] Shaw:0x100001050 Shaw:0x100001050 Shaw:0x100600380
 -- :::] Shaw:0x100001050 ShawandRoot:0x100103870 Shaw:0x100600380

用copy方法复制NSString对象, 出于性能原因, 既然二者本身都不可变,那么不如直接返回源对象,所以二者返回地址一样,所以是浅复制,也就相当于对源对象做retain

因为strCopy是NSString对象,执行第12行代码,是开辟了另一块空间(0x100103870)的,并没有改变之前那块空间(0x100001050)的对象.

        // 复制可变对象

        NSMutableString *mStr = [NSMutableString stringWithString:@"Shaw"];
        NSMutableString *strMCopy = [mStr mutableCopy];
        NSString *strCopy = [mStr copy]; 
//        NSLog(@"%@:%p %@:%p %@:%p",mStr,mStr,strMCopy,strMCopy,strCopy,strCopy);

        NSString *mStrCopy = [mStr copy]; // 打印结果可以看出mStrCopy和strCopy其实是同一个对象,也就是说可变对象的copy只能新开一块空间出来,之后再copy也都是指向这块空间的对象。

        NSLog(@"%@:%p %@:%p %@:%p %@:%p",mStr,mStr,strMCopy,strMCopy,strCopy,strCopy,mStrCopy,mStrCopy);

        strMCopy = [strMCopy stringByAppendingString:@"andRoot"]; // 会放在新地址
        strCopy = [strCopy stringByAppendingString:@"andRoot"];  //  会放在新地址

        NSLog(@"%@:%p %@:%p %@:%p",mStr,mStr,strMCopy,strMCopy,strCopy,strCopy);

//  输出结果

-- :::] Shaw:0x100400290 Shaw:0x1004004d0 Shaw:0x7761685345 Shaw:0x7761685345
-- :::] Shaw:0x100400290 ShawandRoot:0x100400900 ShawandRoot:0x100400550

为什么NSString对象在@property属性声明时写的是copy?

// 假设Person类中有声明如下
// .h

@property (nonatomic, copy) NSString *name;

// main.m

Person *per = [Person alloc] init];
NSMutableString *mStr = [NSMutableString stringWithFormat:@"Root"];
per.name = mStr;
NSLog(@"name is %@ now", per.name);
[mStr appendString:@"andShaw"];
NSLog(@"name is %@ now ", per.name);

// 输出结果会是这样
name is Root now
name is Root now

而将copy改为retain

输出结果会是

name is Root now

name is RootandShaw now

set方法的例子

setName:(NSString *)name {
    if (_name != name) {
        [_name release];
        _name = [name retain];     // copy时此处将retain换成copy
    }
}

总结:

复制方法存在的目的就是为了复制出一个当对它做出改变而不会影响源对象的对象.

当然如果想改变一个NSString对象也不是不可以

比如

NSString *str =@"Shaw";
NSLog("str = %@, addr = %p", str, str);
NSString *__strong *p = &str;
*p = @"Root";
NSLog("str = %@, addr = %p", str, str);

//  输出结果在同一个地址,且已经改变

至于__strong ,  是对象ownership的话题了.


  • retain weak strong(用rayWenderlich的文章来说)

  weak strong是ARC引入的关键词。

  strong指针

  NSString *firstName = @"Ray";

  firstName这个strong指针拥有@"Ray"对象

  

  此时猜想一个textField,当输入Ray

  self.textField.text = @"Ray";

  此时有两个strong指针指向此对象

textField中的文字变化 变成Rayman

此时就变成下图的样子

只有当firstName被赋予新值,或者含有此局部变量的方法结束,或者因为firstName是一个实例变量且它所属的那个对象已经deallocated,这种所有权才结束。

当@"Ray"不再被任何强指针拥有,它就被释放了。

把firstName和self.textField.text这种指针称为strong指针,因为它们使对象存在于内存中。

默认情况下的实例变量,局部变量都是强指针。

weak指针

__weak NSString *weakName = self.textField.text;    //  weak指针是需要显式声明的,用__weak关键字

weakName指向对象但并没有拥有它,如果textField内容发生变动,那么@"Rayman"对象不再被任何强指针指向,它会被释放掉。

weak比assign多了一个作用就是当它指向的对象已经被销毁了,它会自己置成nil。

这是非常方便的,因为这防止弱指针继续指向那片已经被释放了的空间,曾经因为这个问题造成了很多bug,你也许有听过"悬摆指针""野指针",但是有了weak指针,这些问题不会出现了。

weak指针多数被用到有父子关系的两个对象上,父对象用strong指向子对象,子对象用weak指向父对象,这样就避免了内存循环,下面是一个例子。

如果是从storyboard中连了线到代码块的,那都是添加到了父视图的子视图树里的,也就是说是有父对象的强指针指向的

 //
 //  ViewController.h
 //  test2
 //
 //  Created by Shaw on 16/4/6.
 //  Copyright © 2016年 Shaw. All rights reserved.
 //

 #import <UIKit/UIKit.h>

 @interface ViewController : UIViewController

 @property (weak, nonatomic) IBOutlet UITableView *tableView;

 @property (nonatomic,weak) UIScrollView *scrollView;

 @end
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(, , , )];
    _scrollView = scrollView;
    [self.view addSubview:self.scrollView];

}

这几句代码可以用下图来描述:

担心scrollView对象有两个强指针指向不好释放?

scrollView变量是个局部变量,出了那个方法,就被释放掉了,之后就只有self一个强指针指向它了。

retain

retain在ARC下是不能显式写的,但是在@property(nonatomic,retain)这样写是没问题的。

retain的属性的setter是先release旧值,再retain新值:

@property (nonatomic,retain) NSString *string;   // 当赋给string属性的对象总是NSString *,那么用retain和copy都是一样的

-(void)setString:(NSString *)str{

//  if(str == _string){

//    return;

// }

  [_string release];

  _string = [str retain];

}

NSString NSMutableString copy mutableCopy retain weak strong整合的更多相关文章

  1. IOS开发copy,nonatomic, retain,weak,strong用法

     readwrite 是可读可写特性;需要生成getter方法和setter方法时  readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变  ass ...

  2. nonatomic, retain,weak,strong用法详解

    strong weak strong与weak是由ARC新引入的对象变量属性 ARC引入了新的对象的新生命周期限定,即零弱引用.如果零弱引用指向的对象被deallocated的话,零弱引用的对象会被自 ...

  3. Objective-C 中的 assign, copy,retain,strong,weak 详解

    在IOS开发中,经常会使用   @property(nonatomic,copy)NSString * name;   语句来快速设置set get 方法,在此依次说明atomic .nonatomi ...

  4. 【整理】Object-C中的属性(Property)的Setter:assign,copy,retain,weak,strong之间的区别和联系

    iOS编程过程中,经常看到一些属性前面有些修饰符,比如copy,retain等. 这些关键字,是Object-C语言中,对于Property的setter. Mac官网: The Objective- ...

  5. assign, retain, copy, weak, strong

    一.assign, retain, copy 的区别(引用计数 RC reference count) 参考:IOS基础:retain,copy,assign及autorelease 1. 假设你用m ...

  6. iOS开发-retain/assign/strong/weak/copy/mutablecopy/autorelease区别

    依旧本着尊重原创和劳动者的原则,将地址先贴在前面: http://www.cnblogs.com/nonato/archive/2013/11/28/3447162.html,作者Nonato 以下内 ...

  7. 【iOS atomic、nonatomic、assign、copy、retain、weak、strong】的定义和区别详解

    一.atomic与nonatomic 1.相同点 都是为对象添加get和set方法 2.不同点 atomic为get方法加了一把安全锁(及原子锁),使得方法get线程安全,执行效率慢 nonatomi ...

  8. iOS中assign,copy,retain之间的区别以及weak和strong的区别

    @property (nonatomic, assign) NSString *title; 什么是assign,copy,retain之间的区别? assign: 简单赋值,不更改索引计数(Refe ...

  9. copy,retain,assign,strong,weak的区别

    引用地址:http://www.aichengxu.com/view/32930 一.assign,copy,retain 1.copy是内容复制,新建一个相同内容的不同指针,retain为指针复制, ...

随机推荐

  1. netbeans下将全部jar包打成一个,俗称fat jar

    netbeans的java项目中.默认会将配置好的外部引用jar包,复制到dist文件夹的lib文件夹中去.假设须要公布出去.就须要将dist文件夹生成的jar和lib文件夹都拷贝出去公布,不方便. ...

  2. SilkTest天龙八部系列4-ChildWin

    一直觉得SilkTest的ChildWin不好理解,今天大致看了一下,其实它和DialogBox每啥区别,也是一种window类型.帮助里面说,典型的ChildWin就是文档窗口.在Windows上, ...

  3. iotop,pt-ioprofile : mysql IO负载高的来源定位

    http://www.cnblogs.com/cenalulu/archive/2013/04/12/3016714.html 前言: 在一般运维工作中经常会遇到这么一个场景,服务器的IO负载很高(i ...

  4. direct3D directX

    direct3D只是directX其中一个增强功能 DirectX是由很多API组成的,按照性质分类,可以分为四大部分,显示部分.声音部分.输入部分和网络部分. 显示部分担任图形处理的关键,分为Dir ...

  5. phpcms 源码分析三:common.inc.php

    这次是逆雪寒分析common.inc.php的数据库部分: <?php // 包含数据库操作类,下章详说 require PHPCMS_ROOT.'/include/'.$db_file.'.c ...

  6. Http协议三次握手过程

    TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...

  7. 利用QT制作我们自己的一个计算器

    有了前面的经验就比较容易创建一个 属于我们自己的计算器了. 一些简单的拖拽就可以实现了. 界面设计部分: 转到槽之后的代码部分: #include "widget.h" #incl ...

  8. 读取properties文件

    假设项目名称为myproject public class UtilConfig { private static final Properties prop; static { prop = new ...

  9. 在Vivado中调用ModelSim生成FSM的状态转移图

    如果我们已经书写了一段FSM代码,现在想倒过来把它转换成为状态转移图,方便我们直观地检查我们书写的状态对不对(在写论文什么的画图太麻烦的时候,有个自动生成的是多方便啊!),应该怎么弄呢?通过在Viva ...

  10. Javaweb入门20160301 ---xml入门

    一.xml语法 1.文档声明 用来声明xml的基本属性,用来指挥解析引擎如何去解析当前xml 通常一个xml都要包含并且只能包含一个文档声明 xml的文档必须在整个xml的最前面,在文档声明之前不能有 ...