iOS知识梳理 - Objective C的@property、@synthesize和@dynamic

objc推荐咱们经过set/get方法访问对象的属性。很显然,为每个属性手动添加set/get方法的声明和实现是个性价比很低的重复劳动。所以,objc提供了一些关键字帮助咱们简化这一过程。实际上就是这么回事儿。html

@property

首先来看如今的property:xcode

例如:bash

@interface ViewController : UIViewController
@property (nonatomic,assign) BOOL testVar;
@end
复制代码

简单理解,至关于声明了成员变量_testVar,声明了实现了set方法setTestVar、get方法testVar,等价于:app

@interface ViewController : UIViewController
{
    BOOL _testVar;
}
- (void)setTestVar:(BOOL)newTestVar;
- (BOOL)testVar;
@end

@implementation ViewController
- (void)setTestVar:(BOOL)newTestVar
{
    _testVar = newTestVar;
}
- (BOOL)testVar
{
    return _testVar;
}
@end
复制代码

@synthesize

@synthesize能够指定set/get方法的实现。ide

1. 默认

默认地,@synthesize会生成一个同名的成员变量做为set/get的目标。ui

例如:this

@interface ViewController : UIViewController
@property (nonatomic,assign) BOOL testVar;
@end
  
@implementation ViewController
@synthesize testVar;
@end
复制代码

等价于:atom

@interface ViewController : UIViewController
{
    BOOL testVar;
}
- (void)setTestVar:(BOOL)newTestVar;
- (BOOL)testVar;
@end

@implementation ViewController
- (void)setTestVar:(BOOL)newTestVar
{
    testVar = newTestVar;
}
- (BOOL)testVar
{
    return testVar;
}
@end
复制代码

能够看到,set/get方法指向了成员变量testVar,也不会再默认生成_testVarspa

注意,不少人误认为@synthesize默认生成的成员变量是_testVar,据我所知这是不对的。code

官方文档

Important: If you use @synthesize without specifying an instance variable name, like this:

@synthesize firstName;
复制代码

the instance variable will bear the same name as the property.

In this example, the instance variable will also be called firstName, without an underscore.

2. 指定

@synthesize也能够指定一个成员变量做为其set/get的目标。

例如:

@interface ViewController : UIViewController
{
    BOOL exampleVar;
}
@property (nonatomic,assign) BOOL testVar;
@end
  
@implementation ViewController
@synthesize testVar = exampleVar;
@end
复制代码

等价于:

@interface ViewController : UIViewController
{
    BOOL exampleVar;
}
- (void)setTestVar:(BOOL)newTestVar;
- (BOOL)testVar;
@end

@implementation ViewController
- (void)setTestVar:(BOOL)newTestVar
{
    exampleVar = newTestVar;
}
- (BOOL)testVar
{
    return exampleVar;
}
@end
复制代码

此时set/get方法就指向了成员变量exampleVar

特别的,能够声明并指定成员变量_testVar,例如:

@interface ViewController : UIViewController
{
    BOOL _testVar;
}
@property (nonatomic,assign) BOOL testVar;
@end

@implementation ViewController
@synthesize testVar = _testVar;
@end
复制代码

这是最符合官方规范的作法:每一个属性对应一个以_开头的成员变量。

能够看出,这种写法跟本文第一部分,只写一个@property的做用是同样的。

一点历史

其实,在xcode4.4(对应clang3.2/LLVM4.0)之前,显式声明_testVar@synthesize testVar = _testVar;是标准作法。那时候只写个@property并不会给你带来成员变量和set/get的实现。

如今的表现是编译器把之前的标准作法化做默认行为的结果。当咱们只声明了@property而没有实现对应的set/get方法时,编译器会默认声明_开头的成员变量并补全set/get的实现。

一个真实案例

最近遇到的问题是一坨老代码,里面用了@synthesize可是彷佛不是很规范,后来维护的人看起来也不太熟悉这几个关键字,照着前人的代码瞎写,最后代码相似下面的:

@interface ViewController : UIViewController
{
    BOOL _testVar;
}
@property (nonatomic,assign) BOOL testVar;
@end

@implementation ViewController
@synthesize testVar;
- (void)viewDidLoad {
    [super viewDidLoad];
    self.testVar = YES;
    if(_testVar){
        [self doSomething];
    }
}
@end
复制代码

能够看到,代码逻辑里用_testVar去作条件判断实际上是彻底无效的。

@dynamic

@dynamic的做用是告诉编译器,此属性对应的set/get方法将会被动态提供。

说得明白一点,其实@dynamic作了两件事:

  1. set/get我会本身提供的,不用帮我生成了
  2. 我会动态提供,没直接写在这里,编译器别给我报错

一般若是用到dynamic的话,这些方法会在消息转发的时候处理,也能够经过runtime的一些机制动态插入。这里有一些例子。

通常开发中基本上不会用到。

相关文章
相关标签/搜索