技术文档iOS专题面试必看

iOS关于属性关键字,你又知道多少?

2016-11-07  本文已影响3275人  HuyaRC

分享是每个优秀的程序员所必备的品质


一、@property

使用“自动合成”( auto synthesis)这个过程由编译器在编译阶段执行自动合成,所以编译器里看不到这些“合成方法”(synthesized method)的源代码。除了生成getter、setter方法之外,编译器还要自动向类中添加成员变量(在属性名前面加下划线,以此作为实例变量的名字)反编译相关的代码大致生成:

OBJC_IVAR_$类名$属性名称        // 该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表 示该变量距离存放对象的内存区域的起始地址有多远

实际流程:
每次增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在 prop_list 中增加一个属性的描述,计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现。
在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转。

二 、 readwrite,readonly,assign,retain,copy,nonatomic,atomic,strong,weak属性的作用分别是什么。

关键字 注释
readwrite 此标记说明属性会被当成读写的,这也是默认属性。
readonly 此标记说明属性只可以读,也就是不能设置,可以获取。
assign 不会使引用计数加1,也就是直接赋值。
retain 会使引用计数加1。
copy 建立一个索引计数为1的对象,在赋值时使用传入值的一份拷贝。
nonatomic 非原子性访问,多线程并发访问会提高性能。
atomic 原子性访问。
strong 打开ARC时才会使用,相当于retain。
weak 打开ARC时才会使用,相当于assign,可以把对应的指针变量置为nil。

三 、什么情况使用 weak 关键字,相比 assign 有什么不同?

首先明白什么情况使用 weak 关键字?

在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如:

delegate 代理属性,代理属性也可使用
assign自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak
自定义IBOutlet 控件属性一般也使用weak;当然,也可以使用 strong,但是建议使用 weak

weak 和 assign 的不同点:

四、使用 atomic 一定是线程安全的吗?

例如:

声明一个 NSMutableArray 的原子属性 stuff,此时 self.stuff 和 self.stuff =othersulf 都是线程安全的。但是,使用[self.stuff objectAtIndex:index]就不是线程安全的,需要用互斥锁来保证线程安全性。

五、@synthesize 和 @dynamic 分别有什么作用

编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定

六、ARC 下,不显式指定任何属性关键字时,默认的关键字都有哪些?

基本数据: atomic,readwrite,assign
普通的 OC 对象: atomic,readwrite,strong

七、@synthesize 合成实例变量的规则是什么?假如 property 名为 foo,存在一个名为_foo 的实例变量,那么还会自动合成新变量么?

先回答第二个问题:不会!!!不会!!!不会!!!
@synthesize 合成成员变量的规则,有以下几点:

@interface XMGPerson:NSObject
@property (nonatomic, assign) int age;
@end
@implementation XMGPerson
// 不加这语句默认生成的成员变量名为_age
// 如果加上这一句就会生成一个跟属性名同名的成员变量

如果是 @synthesize foo = _foo; 就不会生成成员变量了

八、在有了自动合成属性实例变量之后,@synthesize 还有哪些使用场景?

首先的搞清楚什么情况下不会 autosynthesis(自动合成):

在 @protocol 中定义的所有属性在 category 中定义的所有属性重载的属性,当你在子类中重载了父类中的属性,必须使用@synthesize 来手动合成ivar。
应用场景:
当你同时重写了 setter 和 getter 时,系统就不会生成 ivar。这时候有两种选择手动创建ivar

九、怎么用 copy 关键字?

十、用@property 声明的 NSString(或 NSArray,NSDictionary)经常使用 copy 关键字,为什么?如果改用 strong 关键字,可能造成什么问题?

因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
如果我们使用是 strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.

关键字 注释
浅复制(shallow copy) 在浅复制操作时,对于被复制对象的每一层都是指针复制。
深复制(one-level-deep copy) 在深复制操作时,对于被复制对象,至少有一层是深复制。
完全复制(real-deep copy) 在完全复制操作时,对于被复制对象的每一层都是对象复制。

非集合类对象的 copy 与 mutableCopy

[不可变对象 copy] // 浅复制 
[不可变对象 mutableCopy] //深复制
[可变对象 copy] //深复制 
[可变对象 mutableCopy] //深复制

类对象的 copy 与 mutableCopy

[不可变对象 copy] // 浅复制 
[不可变对象 mutableCopy] //单层深复制
[可变对象 copy] //单层深复制
[可变对象 mutableCopy] //单层深复

十一、这个写法会出什么问题: @property(copy)NSMutableArray *array;

因为 copy 策略拷贝出来的是一个不可变对象,然而却把它当成可变对象使用,很容易造成程序奔溃这里还有一个问题,该属性使用了同步锁,会在创建时生成一些额外的代码用于帮助编写多线程程序,这会带来性能问题,通过声明 nonatomic 可以节省这些虽然
很小但是不必要额外开销,在 iOS 开发中应该使用 nonatomic 替代 atomic.

十二、如何让自定义类可以用 copy 修饰符?如何重写带 copy 关键字的 setter?

若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopyiog 与NSMutableCopying 协议,不过一般没什么必要,实现 NSCopying 协议就够了

// 实现不可变版本拷贝
- (id)copyWithZone:(NSZone *)zone; // 实现可变版本拷贝
- (id)mutableCopyWithZone:(NSZone *)zone;
// 重写带 copy 关键字的 setter
- (void)setName:(NSString *)name {
    _name = [name copy];
}
上一篇下一篇

猜你喜欢

热点阅读