iOS中@property、@synthesize和@dynamic的区别

2,264 阅读2分钟

@property

@property的含义

用于声明成员变量的 getter/setter方法,编译器实际上是做了两件事,生成getter 和 setter,给类中添加名为属性名前加下划线的实例变量。这个过程叫做自动合成

@property=getter方法+setter方法+Ivar(带下划线的实列变量)

@property的使用

以下代码相当于声明了实现了set方法setName、get方法name,以及实列变量_name

@interface ViewController : UIViewController
@property (nonatomic,copy) NSString* name;
@end

等价于下面代码:

@interface ViewController : UIViewController
{
    NSString* _name;
}
- (void)setName:(NSString*)name;
- (NSString*)name;
@end

@implementation ViewController
- (void)setName:(NSString*)newTestVar
{
    _name = name;
}
- (NSString*)name
{
    return _name;
}
@end

总结

什么时候不会使用自动合成?

  • 同时重写了setter和getter时。
  • 重写了只读属性的getter时。
  • 使用了@dynamic时。
  • 在@protocol中定义的所有属性。
  • 在category中定义的所有属性。
  • 重载的属性

@synthesize

@synthesize的含义

本质是@synthesize可以指定set/get方法的实现,际上就相当于完成自动合成的过程,并且可以让程序员指定实例变量,如果不指定实例变量,那么实例变量默认是属性名。

@synthesize的使用

  • @synthesize默认会生成一个同名的成员变量作为set/get的目标。
@interface ViewController : UIViewController
@property (nonatomic,copy) NSString* name;
@end

@implementation ViewController
@synthesize name;
@end

等价于下面代码:

@interface ViewController : UIViewController
{
    NSString* name;
}
- (void)setName:(NSString*)name;
- (NSString*)name;
@end

@implementation ViewController
- (void)setName:(NSString*)newTestVar
{
   name = name;
}
- (NSString*)name
{
    return name;
}
@end
  • 当然也可以指定一个成员变量
@interface ViewController : UIViewController
@property (nonatomic,copy) NSString* name;
@end

@implementation ViewController
@synthesize name=_testName;
@end
@interface ViewController : UIViewController
{
    NSString* name;
}
- (void)setName:(NSString*)name;
- (NSString*)name;
@end

@implementation ViewController
- (void)setName:(NSString*)newTestVar
{
   _testName = name;
}
- (NSString*)name
{
    _testName name;
}
@end

官方规范的做法

每个属性对应一个以_开头的成员变量,和只写一个@property作用是一样的。

@interface ViewController : UIViewController
{
   NSString* _name;
}
@property (nonatomic,copy) NSString *name;
@end

@implementation ViewController
@synthesize name = _name;
@end

@dynamic

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

@interface ViewController : UIViewController
@property (nonatomic,copy) NSString* name;
@end

@implementation ViewController
@dynamic name;
@end

如果没有提供name对应的setter方法和getter方法,会有什么问题:

  • 编译的时候没问题,但是当程序运行到instance.name =someVar,由于缺setter方法会导致程序崩溃。
  • 当运行到 name = var时,由于缺getter方法同样会导致崩溃。

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