iOS属性关键字

属性的意义

属性的本质就是,实例变量+get+set方法
众多属性关键字是对自动生成的get、set方法进行了修饰。

atomic和nonatomic

什么是原子操作?程序的原子性是什么。

程序的原子性指:整个程序中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。
比如张三给李四转账。
在这里插入图片描述
如果张三的钱扣完,银行系统瘫痪了,怎么办呢?张三的1000块钱会被会没呢,当然不会。这时候你的钱会退回来。也就是说银行的转账业务要么成功张三(1000元)李四(3000元),要么不发生张三(2000元)李四(2000元)。

回到OC

atomic :系统自动生成的getter/setter方法会进行加锁操作;可以理解过读写锁,可以保证读写安全;较耗时;
nonatomic : 系统自动生成的getter/setter方法不会进行加锁操作;但速度会更快;
也就是说atomic保证了读写的原子性。
为什么说atomic线程不安全呢?
单线程安全,多线程不安全。
因为在多线程下得到的数据不可靠。

例子一:

当使用atomic时,虽然对属性的读和写是原子性的,但是仍然可能出现线程错误:当线程A进行写操作,这时其他线程的读或者写操作会因为该操作而等待。当A线程的写操作结束后,B线程进行写操作,然后当A线程需要读操作时,却获得了在B线程中的值,这就破坏了线程安全

atomic保证了读写的安全,没有多条线程同时访问一块共享资源,内部使用自旋锁而不是互斥锁。
这里产生的不符合预期的结果应由程序员承担,atomic起到了作用。
但是这里依然是线程不安全,和多条线程同时读写一样。
这个例子显然不够好,因为你要修改数据,得先读,读完就不一定能写。因为此时其他线程等待读操作后,可能就进行了写。
例子二:

如果定义属性NSInteger i是原子的,对i进行i = i + 1操作就是不安全的; 因为原子性只能保证读写安全,而该表达式需要三步操作:
1、读取i的值存入寄存器;
2、将i加1;
3、修改i的值;
如果在第一步完成的时候,i被其他线程修改了,那么表达式执行的结果就与预期的不一样,也就是不安全的 。

因为它的自旋锁只保证了读和写不在同一时间进行
例子三更好说明:
在这里插入图片描述

atomic结论

使用atomic的关键字是绝对读写安全的。
而属于线程不安全。上面的例子二说明了原因。

先看看源码

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
{
   if (offset == 0) {
       object_setClass(self, newValue);
       return;
   }

   id oldValue;
   id *slot = (id*) ((char*)self + offset);

   if (copy) {
       newValue = [newValue copyWithZone:nil];
   } else if (mutableCopy) {
       newValue = [newValue mutableCopyWithZone:nil];
   } else {
       if (*slot == newValue) return;
       newValue = objc_retain(newValue);
   }

   if (!atomic) {
       oldValue = *slot;
       *slot = newValue;
   } else {
       spinlock_t& slotlock = PropertyLocks[slot];
       slotlock.lock();
       oldValue = *slot;
       *slot = newValue;        
       slotlock.unlock();
   }

   objc_release(oldValue);
}

setter和getter方法都有自旋锁。保证了同一时间只有一个线程在进行读或写操作,而不是(读写)。

readWrite、readOnly

readWrite是默认属性。
如果添加了readOnly,对属性进行写操作会报错
在这里插入图片描述

assign、retain、weak、strong、copy

assign是默认关键字,用来修饰基本数据类型。
对这个关键字声明的属性操作时,retainCount 是一直不变的。
retain关键字。
为什么我们不用assign去声明对象呢?

因为 assign 修饰的对象,在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,造成野指针。访问野指针,会导致程序 crash。
为什么可以用assign修饰基本数据类型?

因为基本数据类型是分配在栈上,栈的内存会由系统自己自动处理回收,不会造成野指针。
assign和retain对应了ARC下的weak和strong。
strong 和copy。
主要看看copy。使用了copy关键字的属性,setter方法会调用copyWithZone:方法,生成对象的副本,可是如果是可变对象,是用来copy关键字,那么它的副本就是不可变的,也就无法调用修改对象的方法。
例如NSMutableArray使用了copy关键字修饰,它就无法调用addobject等方法,会报出无法找到选择子的错误。

参考文章

属性关键字
从源代码理解atomic为什么线程不安全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值