美文网首页
iOS知识梳理2:@property的各种参数

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

作者: 大布溜 | 来源:发表于2017-08-28 18:13 被阅读21次

    @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的各种参数

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