前文说道:关于属性的创建以及部分关键字的解释与区别,进行了一定程度上的解释。
具体可以查看:Objective-C属性关键字浅析(上)
本文会继续阐述一些跟属性关键字有关的一些技术点。
一、@synthesize 和 @dynamic 分别有什么作用?
@property 有两个对应的词,一个是@synthesize,一个是@dynamic。
如果@synthesize 和@dynamic 都没写,那么默认的就是
@syntheszie var = _var;
@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)
假如一个属性被声明为
@dynamic var;
然后你没有提供@setter 方法和@getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter方法会导致程序崩溃;
或者当运行到 someVar = instance.var 时,由于缺 getter 方法同样会导致崩溃。
编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定
二、ARC 下,不显式指定任何属性关键字时,默认的关键字都有哪些?
基本数据:atomic,readwrite,assign
普通的 OC 对象:atomic,readwrite,strong
三、@synthesize 合成实例变量的规则是什么?假如 property 名为 foo,存在一个名为_foo 的实例变量,那么还会自动合成新变量么?
先回答第二个问题:不会!!!不会!!!不会!!!
@synthesize 合成成员变量的规则,有以下几点:
如果指定了成员变量的名称,会生成一个指定的名称的成员变量如果这个成员已经存在了就不再生成了。
如果指定@synthesize foo;就会生成一个名称为 foo 的成员变量,也就是说:会自动生成一个属性同名的成员变量。
@interface XMGPerson:NSObject
@property (nonatomic, assign) int age;
@end
@implementation XMGPerson
// 不加这语句默认生成的成员变量名为_age
// 如果加上这一句就会生成一个跟属性名同名的成员变量
如果是 @synthesize foo = _foo; 就不会生成成员变量了
四、在有了自动合成属性实例变量之后,@synthesize 还有哪些使用场景?
首先的搞清楚什么情况下不会 autosynthesis(自动合成):
- 同时重写了setter和getter时
- 重写了只读属性的getter时
- 使用了@dynamic时
在 @protocol 中定义的所有属性在 category 中定义的所有属性重载的属性,当你在子类中重载了父类中的属性,必须使用@synthesize 来手动合成ivar。
应用场景:
当你同时重写了 setter 和 getter 时,系统就不会生成 ivar。这时候有两种选择手动创建ivar
- 使用@synthesize foo = _foo
- 关联@property与ivar可以用来修改成员变量名,一般不建议这么做,建议使用系统自动生成的成员变量
五、 怎么用copy关键字?
NSString、NSArray、NSDictionary等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary。
为确保对象中的属性值不会无意间变动,应该在设置新属性知识拷贝一份,保护其封装性block,也经常使用copy,关键字block。
使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.
在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但是建议写上 copy,因为这样显示告知调用者“编译器会自动对 block 进行了 copy 操作。"
六、用@property 声明的 NSString(或 NSArray,NSDictionary)经常使用 copy 关键字,为什么?如果改用 strong 关键字,可能造成什么问题?
因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
如果我们使用是 strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
属性 | 内容 |
---|---|
浅复制(shallow copy) | 在浅复制操作时,对于被复制对象的每一层都是指针复制。 |
深复制(one-level-deep copy) | 在深复制操作时,对于被复制对象,至少有一层是深复制。 |
完全复制(real-deep copy) | 在完全复制操作时,对于被复制对象的每一层都是对象复制。 |
复制详解:
属性 | 内容 |
---|---|
浅复制(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协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现NSCopying和NSMutableCopying协议,不过一般没什么必要,实现NSCopying协议就够了
// 实现不可变版本拷贝
- (id)copyWithZone:(NSZone *)zone; // 实现可变版本拷贝
- (id)mutableCopyWithZone:(NSZone *)zone;
// 重写带 copy 关键字的 setter
- (void)setName:(NSString *)name {
_name = [name copy];
}
网友评论