0%

OC property、synthesize、dynamic关键字

OC的变量:

OC有4种基本数据类型:char,int,float,double。它们又有一些限定词:signed,unsigned,short,long,long long。

实例变量和成员变量是一个概念。

@property

@property指令作用:声明了一个属性及属性的两个访问器方法。

如果在@implementation块里@synthesize和@dynamic都没写,那么编译器会帮你自动添加@syntheszie property = _property;有一种情况除外:子类属性和父类属性同名.此时会报警告:

“Auto property synthesis will not synthesize property ‘delegate’; it will be implemented by its superclass, use @dynamic to acknowledge intention”

这个时候就需要自己实现属性了.两种常用解决办法:

1
2
3
1.@dynamic delegate; //表示使用父类的实现,此时子类内部将无法访问_delegate.

2.@synthesize delegate = _delegate; //子类内部可以访问_delegate.

@synthesize和@dynamic

它们都是用于属性实现的.注意是实现不是声明,声明是@property.

@synthesize

1.让编译器为属性自动合成setter/getter方法。如果手动实现了setter/getter方法,则会覆盖自动合成的。

2.为属性按需合成一个实例变量。

按需合成的意思就是说如果你有声明一个下划线属性名_property的实例变量,那么编译器会自动把它关联给这个属性,否则的话会帮你自动声明这个实例变量并关联给这个属性.

语法:@synthesize property = ivar; 或 @synthesize property;

eg:

1
2
3
4
5
@synthesize firstName = _firstName; //属性firstName被指定了一个名为_firstName的实例变量.

@synthesize lastName; //属性lastName被指定了一个名为lastName的实例变量.

@synthesize age = yearsOld; //属性age被指定了一个名为yearsOld的实例变量.

@dynamic

@dynamic关键字功能和@synthesize相反,它是告诉编译器不要自动为这个属性合成setter/getter方法,也不要为属性自动合成一个实例变量(因此在其他方法中是无法使用_property实例变量的).属性的访问器方法将由程序员自己来实现,实现的方式可以是直接提供setter/getter方法的实现,也就是自己在@implementation块里面实现setter/getter方法;也可以是在运行时通过其他机制比如动态的加载一段代码或者通过动态方法解析提供.它可以消除编译器因为找不到属性的访问器方法的实现而产生的警告.使用这个指令的时候你自己必须要清楚的知道这些方法在运行时确实是可用的,如果在运行时依然找到不到这些方法,显然会导致崩溃.

为什么会有dynamic这个关键字?因为系统自动合成的setter/getter方法可能不满足我们的需求,甚至setter/getter方法是通过runtime实现的为了避免重复实现必须要有一种机制阻止系统自动合成setter/getter方法,或者这是一个计算型属性不需要合成相应实例变量。

比如DDLog里面的OSSDDLogFileInfo类中,就有许多这样的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@property (strong, nonatomic, readonly) NSDate *creationDate;
@property (strong, nonatomic, readonly) NSDate *modificationDate;

@property (nonatomic, readonly) unsigned long long fileSize;

@property (nonatomic, readonly) NSTimeInterval age;

@property (nonatomic, readwrite) BOOL isArchived;

....
@interface OSSDDLogFileInfo () {
__strong NSString *_filePath;
__strong NSString *_fileName;

__strong NSDictionary *_fileAttributes;

__strong NSDate *_creationDate;
__strong NSDate *_modificationDate;

unsigned long long _fileSize;
}

@end

@implementation OSSDDLogFileInfo

@synthesize filePath;

@dynamic fileName;
@dynamic fileAttributes;
@dynamic creationDate;
@dynamic modificationDate;
@dynamic fileSize;
@dynamic age;

@dynamic isArchived;


- (NSTimeInterval)age {
return [[self creationDate] timeIntervalSinceNow] * -1.0;
}

- (NSDate *)creationDate {
if (_creationDate == nil) {
_creationDate = self.fileAttributes[NSFileCreationDate];
}

return _creationDate;
}

- (unsigned long long)fileSize {
if (_fileSize == 0) {
_fileSize = [self.fileAttributes[NSFileSize] unsignedLongLongValue];
}

return _fileSize;
}

age只是一个计算型属性,不需要实例变量,所以使用dynamic进行标记。

再比如在CoreData里的NSManagedObject类里面使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@interface MyClass : NSManagedObject{

}

@property(nonatomic, retain) NSString *value;

@end


@implementation MyClass

@dynamic value; //@dynamic 属性名;

@end

另一种用法:子类声明父类的同名属性,这时可以使用dynamic指示编译器使用父类的的存取器和实例变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@protocol FDAnimalDelegate <NSObject>

- (void)run;

@end

@interface FDAnimal : NSObject

@property (nonatomic, assign) NSInteger magCount;

@property (nonatomic, weak) id<FDAnimalDelegate> delegate;

- (void)startRun;

@end

@protocol FDDogDelegate <FDAnimalDelegate>

- (void)fastRun;

@end

@interface FDDog : FDAnimal

@property (nonatomic, assign) NSInteger magCount;

@property (nonatomic, weak) id<FDDogDelegate> delegate;

@end

@implementation FDDog
@dynamic delegate; //指示使用父类的存取器方法,实例变量也使用父类里的。
...
@end

从上面可以看得出来这两个指令功能正好相反.

注意:不能对一个属性同时使用@synthesize和@dynamic.

1
2
3
@dynamic age;

@synthesize age = _age; //报错:Property 'age' is already implemented

上面已经说到@synthesize和@dynamic的作用就是实现某个属性.同时使用的话就重复实现了,当然会报错.

觉得文章有帮助可以打赏一下哦!