美文网首页iOS知识点iOS Developer
OC 属性修饰词retain assign等

OC 属性修饰词retain assign等

作者: 75cec28807b7 | 来源:发表于2017-02-16 11:55 被阅读209次

    #修饰词retain、assign

    ***retain、assign、copy在@property中的使用实际上是通过控制set方法进行内存管理。下面详细介绍:***

    1. retain

    例如:

    ```

    @class Dog

    @property (nonatomic,retain) Dog *dog;

    ```

    **注:nonatomic与atomic相对应,涉及线程,nonatomic相对atomic来说性能高,而声明属性时一般认为atomic,故需在此申明nonatmic**

    这里使用了retain,那么set方法中,究竟如何体现

    ```

    - (void)setDog:(Dog *)dog

    {

    if (_dog != dog) { //判断是否需要重新赋值

    [_dog release]; //释放旧引用,计数器-1

    _dog = [dog retain]; //重新赋值,计数器+1

    }

    }

    ```

    2. assign:

    例如:

    ```

    @property (nonatomic,assign) int count;

    ```

    这里使用了assign,那么在set方法中,究竟如何体现

    ```

    - (void)setCount:(int)count

    {

    _count = count;

    }

    ```

    3. copy:

    例如:

    ```

    @property(nonatomic,copy)NSString *str;

    ```

    这里使用了copy,那么在set方法中

    ```

    - (void)setStr:(NSString *)str

    {

    if(_str != str) { //判断是否需要重新赋值

    [_str release]; //释放旧引用,计数器-1

    _str = [str copy]; //重新赋值,使用copy

    }

    }

    ```

    ##总结:

    1. retain:先release旧值,在retain新值,在上例中_dog与dog最终指向同一块内存区域。

    2. assign:直接赋值,不考虑内存管理。

    3. copy:先release旧值,再copy新值,copy的本质为复制该内所存储的内容,重新创建一个对象赋给其相同的内容,很明显,在copy这个过程中也发生了一次retain,不过这是个全新的对象。在上例中,_str与str最终指向了不同的区域,但其内容一样。

    4. 从retain、assign、copy的特点中:

    retain一般适用于OC中的对象

    assign一般适用于非OC对象,如int等普通类型

    copy一般适用于NSString等不可变的对象,因为是重新创建了对象,并且内容不变,因此不用担心后面的操作会对该属性的值产生影响。

    ##实例分析:

    假设str为对象p的属性

    ```

    @property (nonatomic,copy)NSString *str;

    NSMutableString *s = [[NSMutableString alloc] initWithString:@"hello"];

    p.str = s; //此时,str的值为@”hello“

    [s appendString:@"world"]; //此时,s的值是”hello world“,但是str的值依然为”hello“。

    ```

    但是如果开始时str的申明为:

    ```

    @property(nonatomic,retain)NSString *str;

    ```

    那么,在进行完[s appendString:@"world"]之后,str的值将变为”hello world“。因为str与s共用一块内存,内容完全相同,而s是可以改变的,所以s改变后,str也将改变。

    copy:建立一个索引计数为1的对象,然后释放就对象 对NSString

    对NSString它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。

    retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1

    对其他NSObject和其子类

    对参数进行release旧值,再retain新值

    指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。

    ***注意:把对象添加到数组中时,引用计数将增加对象的引用计数次数+1***

    retain的实际语法为:

    - (void)setName:(NSString *)newName {

    if (name != newName) {

    [name release];

    name = [newName retain];

    }

    }

    copy与retain:

    Copy其实是建立了一个相同的对象,而retain不是:

    比如一个NSString对象,地址为0X1111,内容为@”STR“

    Copy到另一个NSString之后,地址为0X2222,内容相同新的对象retain为1,旧有对象没有变化

    retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1

    也就是说retain是指针拷贝,copy是内容拷贝。

    retain的set方法应该是浅复制,copy的set方法应该是深复制了

    copy另一个用法:

    copy是内容的拷贝,对于像NSString的确实这样

    但是,如果是copy的是一个NSArray呢?

    NSArray *array = [NSArray arrayWithObjects:@"hello",@"world",@"baby"];

    NSArray *array2 = [array copy];

    这个时候,系统的确是为array2开辟了一块内存空间,但是我们要认识到的是,array2中的每个元素,只是copy了指向array中相对应元素的指针。这便是所谓的”浅复制“。

    assign:简单辅值,不更改索引计数

    对基础数据类型(例如NSInteger,CGFloat)和C数据类型(int,float,double,char等)适用简单数据类型

    此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协议,你就要明白指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是可拷贝的。

    weak和strong属性只有在你打开ARC时才会被要求使用,这时你是不能使用retain release autorelease操作,ARC会自动为你做好这些操作,但是你需要在对象属性上使用weak和strong,其中strong就相当于retain属性,而weak相当于assign。

    strong关键字与retain相似,引用计数自动+1,用实例更能说明一切

    @property(nonatomic,strong)NSString *string1;

    @property(nonatomic,string)NSString *string2;

    self.string1 = @"String1";

    self.string2 = self.string1;

    self.string1 = nil;

    NSLog(@"String2 = %@",self.string2);

    结果是:String2 = String1

    ***由于string2是strong定义的属性,所以引用计数+1,使得它们指向同一地址内容为:@”String1“,不可变字符串每次赋值都会重新开辟新地址。***

    接着我们来看weak关键字:

    如果这样声明两个属性:

    @property(nonatomic,strong)NSString *string1;

    @property(nonatomic,weak)NSString *string2;

    self.string1 = @"String1";

    self.string2 = self.string1;

    self.string1 = nil;

    NSLog(@"String2 = %@",self.string2);

    结果是:String2 = null

    ***分析下,由于self.string1与self.string2指向同一地址,且string2没有retain内存地址,而self.string1 = nil释放了内存,所以string1为nil。声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为nil。这样的好处能有效的防止野指针。在c/c++开发过程中,为何大牛都说指针的控件释放后,都要讲指针赋为NULL。在这儿用weak关键字帮我们做了这一步。***

    ##copy

    特点:

    1. 修改源文件的内容,不会影响副文本;

    2. 修改副文本的内容,不会影响源文件;

    OC中copy的作用是:利用一个源对象产生一个副本对象

    特点:

    1. 修改源对象的属性和行为,不会影响副本对象;

    2. 修改副本对象的属性和行为,不会影响源对象。

    如何使用copy功能

    一个对象可以调用copy或mutableCopy方法来创建一个副本对象。

    1. copy:创建的时不可变副本(NSString、NSArray、NSDictionary)。

    2. mutableCopy:创建的可变副本(NSMutableString、NSMutableArray、NSMutableDictionary)。

    使用copy功能的前提:

    1. copy:需要遵守NSCopying协议,实现copyWithZone:方法。

    ```

    @protocol NSCopying

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

    @end

    ```

    2. mutableCopy:需要遵守NSMutableCopy协议,实现mutableCopyWithZone:方法

    ```

    @protocol NSMutableCopying

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

    @end

    ```

    ###深复制和浅复制的区别:

    **深拷贝**

    特点:

    1. 源对象和副本对象是不同的两个对象;

    2. 源对象引用计数器不变,副本对象计数器为1(因为是新产生的)。

    本质:产生了新对象

    **浅拷贝**

    特点:

    1. 源对象和副本对象是同一对象;

    2. 源对象(副本对象)引用计数+1,相当于做一次retain操作。

    本质:没有产生新的对象。

    常见赋值如下:![](http://oh6yavwvf.bkt.clouddn.com/00027.png)

    ***只有源对象和副本对象都不可变时,才是浅复制,其他都是深复制。***

    ```

    /**

    NSMutableString调用mutablecopy:深复制

    */

    void mutableStringMutableCopy()

    {

    NSMutableString *srcStr = [NSMutableString stringWithFormat:@"age is %d",10];

    NSMutableString *copyStr = [srcStr mutableCopy];

    [copyStr appendString:@"abc"];

    NSLog(@"srcStr=%@,copyStr=%@",srcStr,copyStr);

    }

    /**

    NSMutableString调用copy:深复制

    */

    void mutableStringCopy()

    {

    NSMutableString *srcStr = [NSMutableString stringWithFormat@"age is %d",10];

    NSString *copyStr = [srcStr copy];

    [srcStr appendString:@"abc"];

    NSLog(@"srcStr=%p, copyStr=%p", srcStr, copySt);

    }

    /**

    NSString调用mutablecopy:深复制

    */

    void stringMutableCopy()

    {

    NSString *srcStr = [NSString stringWithFormat:@"age is %d",10];

    NSMutableString *copyStr = [srcStr mutableCopy];

    [copyStr appendString:@"abc"];

    NSLog(@"srcStr=%@, copyStr=%@", srcStr, copyStr);

    }

    /**

    NSString调用copy:浅复制

    */

    void stringCopy()

    {

    //copy:产生的肯定是不可变副本

    //如果是不可变对象调用copy方法产出不可变副本,那么不会产生新的对象

    NSString *srcStr = [NSString stringWithFormat:@"age is %d",10];

    NSString *copyStr = [srcStr copy];

    NSLog(@"%p %p",srcStr,copyStr);

    }

    ```

    文章属于摘抄搬砖!

    相关文章

      网友评论

        本文标题:OC 属性修饰词retain assign等

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