Objective-C: @property, @synthesize, @dynamic
yaofly2012 opened this issue · comments
@property
引入背景
先说结论:OC中约定俗成地利用getter/setter方法获取/设置类成员变量值。为了便于声明和定义Getter/Setter方法才引入了@property
。
类成员变量声明和访问
@interface Girl : NSObject {
@public // publick成员变量
NSString *name;
@private // private成员变量
int age;
}
@end
@implementation Girl
- (instancetype)init {
if(self = [super init]) {
self->name = @"Default"; // 利用`->`直接访问成员变量
self->age = 20;
}
return self;
}
@end
Girl *girl = [[Girl alloc] init];
NSLog(@"The girl's name is %@", girl->name);
OC里利用->
直接访问成员变量,那为啥要用getter/setter方式呢?
为啥要用getter/setter方法获取/设置类成员变量值 TODO
Explain Getter and Setters in Objective C :
- 可以在getter和setter中添加额外的代码,实现特定的目的。比如赋值前(set)需要实现一些特定的内部计算,或者更新状态,缓存数据等等。
- KVC(Key-Value Coding)和KVO(Key-Value Observing)都是基于此实现的。
- 在非ARC时代,可以在在getter和setter中进行内存管理。
基本语法
@property(特性1, 特性2 , 特性3)varType varName;
将上面的Demo改用@property
:
// 在@interface里使用@property 声明成员变量
@interface Girl : NSObject
@property (copy) NSString *name; // 头文件里利用@property声明
@property int age;
@end
// 实现
@implementation Girl
- (instancetype)init {
if(self = [super init]) {
self.name = @"Default"; // 利用点`.`操作符访问setter,或者直接调用`setName`方法:` [self setName:@"Default"];`
self.age = 20; // 利用点`.`操作符访问setter,或者直接调用`setAge`方法:` [self setAge:20];`
}
return self;
}
@end
// 使用
Girl *girl = [[Girl alloc] init];
NSLog(@"girl's name is %@", girl.name); // 利用点`.`操作符访问getter,或者`[girl name]`
@property
做了3件事情:
- 在
@interface
里声明成员变量,方法名字格式是:
- getter方法跟变量名一致
- setter方法则是
setXXX
- 在
@interface
里声明声明getter/setter方法; - 在
@implementation
定义getter/setter方法。
注意:
@property
须在@interface
使用,不可以在@implementation
里使用。- 利用点
.
操作符访问既可以访问getter,也可以访问setter。如果采用[]
方式就比较繁琐些。
特性
可使用的修饰关键字根据功能可分为5类(主要用到的前3类):
- 原子特性:
atomic
,nonatomic
,默认值atomic
- 访问特性性:
readonly
,readwrite
,默认值readwrite
- 内存管理特性:
assign
,retain
,copy
默认值assgin
ARC之后针对对象类型的变量增加了weak
、strong
特性,默认值strong
assign/retain/copy
和weak/strong
是互斥的,不可同时使用。
7. getter=
/ setter=
自定义存取函数名称
8. 可空特性Nullability:
nullable
:可空nonnull
:不可控null_unspecified
:未指定null_resettable
:调用setter
去reset属性时,可以传入nil
,但是getter
返回值,不为空。UIView
下面的tintColor
,就是null_resettable
。这样就保证,即使赋值为nil
,也会返回一个非空的值
最佳实践
Assigning retained object to weak property; object will be released after assignment
Property attributes 'assign' and 'strong' are mutually exclusive
参考
@synthesize
在protocol
里使用@property
除了可以在@interface
使用@property
,protocol
里也使用@property
。
@protocol Person
@property (copy) NSString *name;
@property int age;
@end
@interface Girl : NSObject<Person>
@end
此时XCode会有个告警:
Auto property synthesis will not synthesize property 'age' declared in protocol 'Person'
Auto property synthesis will not synthesize property 'name' declared in protocol 'Person'
协议里只有声明并没有实现,所以得需要实现类去实现。实现类正确的做法是用@synthesize
声明实现:
@implementation Girl
@synthesize name;
@synthesize age;
- (instancetype)init {
if(self = [super init]) {
self.name = @"Default";
[self setAge:20];
}
return self;
}
@end
@synthesize
只能在实现类的@implementation
里使用,不可以在@interface
里使用。
综上:
- 协议里的
@property
的作用是声明成员变量,声明getter/setter
方法; @synthesize
的作用是实现属性的getter/setter
方法
如果覆盖@protocol
里的@property
会怎样?
不要这样做。可参考OC 中,覆盖属性会有怎么样的化学反应?