iOS知识梳理2:@property的各种参数


@property 在.h文件中声明方法的权限和环境等.

@synthesize 在.m中实现getter方法和setter方法,在Xcode4.2以及以后的版本可以省略掉
(实际就是省略掉get和set方法的一种声明,现在甚至连这个声明都不用了直接可以省略掉)


@property的格式:

@property (参数1,参数2) 类型 名字;

参数:
读写属性(readwrite/readonly)
原子性(atomic/nonatomic)
非ARC:
setter语意(assign/retain/copy)
ARC:
所有者特性(strong/weak)


逐个解析:

1.读写属性(readwrite/readonly)

简单易懂,读写或者只可读.

2.原子特性(atomic/nonatomic)

主要用于多线程,当不同线程访问同一个资源时,很容易引起数据错乱和数据安全问题.

为属性加锁可以解决这个问题(具体在后面多线程里面有解析,后续整理出来后,我把链接贴到这里)

atomic:原子属性,为setter方法加锁
nonatomic:非原子属性,不会为setter方法加锁.

一般我们开发都会使用nonatomic,因为atomic消耗很大,自己编程时注意避免多个线程抢夺一个资源就好.

3.setter语义(assign/retain/copy)

(这个很重要啊!!!!重点啊!!!记笔记啊!!!!面试经常被问到啊!!!!)

这个属性主要告诉xcode如何实现setter方法,针对非ARC才有这个属性.

assign:简单赋值,不会改变引用计数,默认类型

-(void)setStr:(NSString *)value
{
       str = value;
}

retain:释放旧对象,将就对象的值赋予输入的对象,引用计数加1.

-(void)setStr:(NSString *)v
{
      if(v!=str){
          [str release];
          [str retain];
      }
}

copy:和retain一样,只是retain换成了copy

-(void)setStr:(NSString *)v
{
      if(v!=str){
          [str release];
          [str copy];
      }
}
补充1.什么时候使用?

答:
a.值类型和简单类型用assign.比如,NSInterger,CGPoint,CGFloat,int,double,float等

b.对含有可深复制子类的对象,用copy.比如NSArray,NSString,NSSet,NSDictionary,NSData等.
("可深复制的子类"比较不好理解,可以和补充3对照来看)

c.其他的NSObject对象用retain

补充2.深复制/浅复制 copy/retain

答:
深复制copy: 内容拷贝,源对象和副本对象是两个不同的对象,源对象应用计数不变,副本对象应用计数加1.
浅复制retain: 指针拷贝,源对象和副本对象指的是同一个对象,对象应用计数加1,相当于retain.
(只有不可变对象创建不可变副本copy才是浅复制,其他的copy都是深复制)

补充3.为什么用NSString,NSArray要用copy?

如果用retain,如果赋值的是一个NSMutableString类型,那么当你在外部修改值的时候,你的属性也跟着改变了.
如下:

@property (nonatomic,copy) NSArray *copyarray;

@property (nonatomic,retain) NSArray *retainarray;

NSMutableArray *str = [NSMutableArray arrayWithObjects:@"1",@"2", nil];

self.copyarray = str;
self.retainarray = str;

[str addObject:@"3"];

NSLog(@"%@",self.copyarray);
NSLog(@"%@",self.retainarray);
2017-08-28 14:37:03.495 test3[32985:3406085] (
    1,
    2
)
2017-08-28 14:37:03.495 test3[32985:3406085] (
    1,
    2,
    3
)

4.所有者特性(strong/weak)

ARC情况下没有assign/retain/copy, 改为strong/weak 强引用或弱引用。

strong。默认情况下,指针都是__strong,当所有强引用都去除时,对象才能被收集和释放。
weak。一些集合类(NSArray, NSSet, NSOrderedSet 和 NSDictionary等)不应增加其原素的引用,会引起对象无法释放。使用__weak弱引用关键字。当被引用的对象消失时,弱应用自动设置为nil。

总结:一旦最后一个指向对象的strong类型的指针离开,这个对象释放,如果这个时候还有weak指针指向改对象,则会消除掉所有剩余的weak指针。

strong相当于retain,而weak相当于assign

只有一种情况下需要使用weak,避免retain cycles(就是父类中含有子类{父类retain了子类},子类又调用了父类{子类又retain了父类},这样就都无法release了,所以要使用弱应用)

另一个作者,举出的简单易懂的strong/weak区别的例子,觉得不错链接放在这里

问题1: xib/storyb0ard连接的对象为什么可以使用weak?

答:

@property (nonatomic, weak) IBOutlet UIButton *button;

比如像这样的代码,在连接时自动生成为weak。因为这个button已经放到view上了,因此只要这个View不被释放,这个button的引用计数都不会为0,因此这里可以使用weak引用。
(在UIViewController的头文件里可以看到这个view是retain类型的属性(也就是强引用);添加到view上的子控件就会被view的subviews属性维护起来(view的subviews属性是copy类型也是强引用).)

为题2:如果不使用xib/storyboard链接,直接用代码,可以使用weak声明UIView吗?

答:
不行,

@property (nonatomic, weak) UIButton *button;

比如这样的代码,使用self.button = [[UIButton alloc] init]的时候,xcode会报警告,而且,引用计数为0,无法生成变量,只有再指向一个强引用的对象。所以代码创建UIView时最好使用strong。

补充:看到一个流传很广的帖子比喻strong和weak的区别。

他比喻说,对象是狗,强引用是牵狗的绳子,弱应用是不远的地方看着狗的小孩。

当有五个指针强引用一个对象时,就相当于五个绳子牵着狗。只有五条绳子全部都去掉的时候狗才能跑。只要还有一条绳子在,狗就不能跑,孩子也能看到狗。一旦没有绳子了,狗就跑了,孩子也就看不到狗了,也就是弱引用也为nil了。。。。还挺有意思。。。

block在使用时也会遇到一些strong和weak相关的问题,在我们复习到block的时候再回来看吧,
先留一个别人家的链接

关于拷贝的一个还不错的文章

你可能感兴趣的:(iOS知识梳理2:@property的各种参数)