OC语言之属性关键字

属性关键字

读写权限

  • readonly
  • readwrite(默认)

原子性

OC中的属性可以修饰成nonatomic和atomic,即原子和非原子属性。atomic属性设计的出发点是保证多线程下使用属性的安全性,

  • atomic(默认)

atomic修饰的属性可以保证赋值和获取值(对成员属性的直接获取和赋值,并不代表操作和访问),线程安全。

假如一个atomic修饰的的数组,对数组进行赋值和获取可以保证线程安全,如果对数组进行操作,比如给数组添加对象或移除对象元素,则不在atomic的负责范围内,没办法保证数组的线程安全。

使用atomic修饰的属性并不会线程安全

源码objc4-750.1

void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}
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);
}

从使用PropertyLocks数组中的一个给写操作上锁,在赋完值之后进行解锁操作。

也就是说,atomic只是在 setter方法 中加锁,当多个线程同时写操作时,要进行排队。A线程对属性进行写操作,B线程不可以对该属性进行写操作,只有等A线程访问结束,B线程才能操作。问题在于,当A线程再想对属性进行读操作,读取的是B线程写的数据,这就破坏了线程安全,。如果再有C线程在A线程读操作前Release这个属性,那么程序就会Crash.
综上,atomic 操作是原子性的,它只保证了属性的setter和getter时的线程安全,并不能保证属性线程安全,atomic的使用只是更好的降低了线程出错的可能性。

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    if (offset == 0) {
        return object_getClass(self);
    }

    // Retain release world
    id *slot = (id*) ((char*)self + offset);
    if (!atomic) return *slot;
        
    // Atomic retain release world
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();
    id value = objc_retain(*slot);
    slotlock.unlock();
    
    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
    return objc_autoreleaseReturnValue(value);
}
  • nonatomic

atomic 与 nonatomic 的区别如下:

  1. atomicnonatomic的本质区别其实也就是在setter方法上的操作不同,atomic保证了gettersetter存取方法的线程安全,两者都不能保证整个对象是线程安全的。
  2. nonatomic的速度要比atomic的快。

鉴于以上两点,大部分使用的是nonatomic这个属性。

那么问题来了,Apple为什么只给setter和getter方法加锁而不直接使用@synchronized加锁呢?

看看 synchronized 操作的源码, 简单的一个注解,其实做了许多事情,每个@synchronized()代码块,使用了 objc_sync_enterobjc_sync_exitid2data三个加解锁序列,而这种作法相比使用一个atomic来修饰,只给settergetter方法加锁的方式 在性能上要慢很多。读写操作一个属性时,通常需要很快来完成,atomic的方式要适合这项工作。

在必要时,可以使用@synchronized,但是在保证多线程操作在发生错误的时候,不会发生dead lock。

引用计数

retain/strong(修饰对象的)

assign/unsafe_unretained(基本数据类型或对象)

assign与weak的区别有哪些?

  • assign修饰基本数据类型,如int,BOOL

  • assign修饰对象类型时,不改变其引用计数。

  • 会产生悬垂指针。

    assign修饰的对象在被释放之后,其assign指针仍然指向原对象内存地址,这个时候如果通过assign指针继续访问对象,可能会由于悬垂指针的原因导致内存泄漏,或程序异常。

  • weak不改变被修饰对象的引用计数

  • 所指对象在被释放之后会自动置为nil

  • weak之修饰对象

copy

copy关键字.png
  • 可变对象的copymutableCopy都是深拷贝。
  • 不可变对象的copy是浅拷贝,mutableCopy是深拷贝。
  • copy方法返回的都是不可变对象;

深拷贝与浅拷贝

浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。

  1. 会增加对象的引用计数
  2. 没有发生新的内存分配。

深拷贝让目标对象指针和源对象指针指向两片内容相同的内存空间。

  1. 不会增加对象的引用计数
  2. 产生了新的内存空间分配
@property(copy) NSMutableArray *array;

如果像上面那样声明一个成员属性会导致什么问题?

  1. 如果赋值过来的是NSMutableArray,copy之后是NSArray

  2. 如果赋值过来的是NSArray,copy之后是NSArray

    所以无论被赋值过来的是NSMutableArray,还是NSArray copy的结果都是不可变对象,由于原来的属性被声明为

    NSMutablArray就不可避免的有调用方调用其进行元素的添加与移除,此时由于copy的结果是NSArray,调用其子类方法的添加与移除会造成程序的崩溃。

OC语言笔试题

MRC下如何重写retain修饰变量的setter方法?

@property(nonatomic, retain) id obj;
- (void)setObj:(id)obj
{
  if(_obj != obj) { //防止提早释放了对象
    [_obj release];
    _obj = [obj retain];
  }
}

请简述分类实现原理?

KVO的实现原理是怎样的?

能否为分类添加成员变量?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 307、setValue:forKey和setObject:forKey的区别是什么? 答:1, setObjec...
    AlanGe阅读 1,545评论 0 1
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,142评论 0 12
  • 已经回到湛江 最重要的事情还没完成 计划 目标 今天还是没能, 静下心来, 去做一些事。 工作上不要急 做好提前量...
    魔山乐水阅读 30评论 0 0
  • 以下提示为了大家便于查找日课,如果有更好的建议希望大家分享。谢谢! 快速找到今日日课 快速浏览日课 快速查询日课递...
    周洋_图乐园阅读 178评论 0 0