美文网首页iOS面试总结
OC语言之属性关键字

OC语言之属性关键字

作者: Jimmy_L_Wang | 来源:发表于2019-06-14 22:17 被阅读0次

属性关键字

读写权限

  • 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的实现原理是怎样的?

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

相关文章

  • OC语言之属性关键字

    属性关键字 读写权限 readonly readwrite(默认) 原子性 OC中的属性可以修饰成nonatomi...

  • OC属性关键字

    1.读写权限:readonly,readwrite(默认) 2.原子性: atomic(默认),nonatomic...

  • Swift OC 混编 Model类的设置

    在OC中model类的属性大多如下设置(记得要根据需求换关键字,不是本篇重点) 因为OC中属性为nil时并不会引发...

  • 【知识总结】OC中的继承

    关键字 OC中也可以使用上面的关键字设置属性的权限。在OC中,默认情况下,在头文件中实现的是public,在m文件...

  • weak的底层实现原理?

    1.何为weak? weak 是oc中定义对象属性property时用于修饰对象属性的关键字。 2.weak有什么...

  • OC由浅入深系列 之 属性

    一、什么是属性 在OC中,用@property 关键字修饰的类的成员成为属性。 在属性出现之前,声名一个实例变量通...

  • iOS9新特性之常见关键字

    苹果为什么要推出关键字? 迎合swift,swift强语言,OC弱语言,swift必须描述属性有没有值 关键字注意...

  • 访问并修改一个类的私有属性

    在OC中的类会有某些私有属性,这些属性通常写在.m文件中或在.h文件中用@private关键字进行修饰。某些...

  • oc属性关键字整理

    看面试题的经常看到一些关于关键字的问题,在oc中修饰一个属性一般有4种关键词 原子性--- atomic/nona...

  • OC属性常用关键字

    含义: copy 复制内容(深复制),如果调用copy的是数组,则为指针复制(浅复制),仅仅复制子元素的指针。 @...

网友评论

    本文标题:OC语言之属性关键字

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