iOS知识点iOS Developer

OC 属性修饰词retain assign等

2017-02-16  本文已影响209人  75cec28807b7

#修饰词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);

}

```

文章属于摘抄搬砖!

上一篇下一篇

猜你喜欢

热点阅读