您的位置:首页 > 移动开发 > IOS开发

如何正确使用@synthesize(在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?)

2016-09-21 18:21 876 查看
作者:代培

地址:http://blog.csdn.net/dp948080952/article/details/52611348

转载请注明出处

写在前面

这篇博客本来是回答《招聘一个靠谱的iOS》中在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景? 的这一问题,但是写着写着在了解了property的相关内容后,突然冒出了许多对@synthesize使用方法的理解,并且记录了下来,希望分享给大家,与大家一同进步,如果理解的不正确,欢迎在评论区指正,有评论必回!

正文

所有场景

同时重写了setter和getter函数

重写了只读属性property的getter(这里property必须声明在.m文件中)

想要自定义实例变量的变量名

声明在@protocol中的property

重载的属性

最好不要在手动管理使用

从前两点来看,当你准备自己手动管理property的所有内容时,编译器就不会帮你自动生成,此时就需要用到@synthesize手动生成(需要注意的是@synthesize必须要写在@implementation中)。

其实对于前两种情况,我觉得是不适合使用@synthesize的,为什么呢?首先要看@synthesize是做什么的,他是帮你自动实现ivar和访问方法,而你已经完全重写了访问方法,此时@synthesize只是让他帮你实现了一个ivar,已经背离了它本身该做的事情,为何不直接自己声明一个ivar呢,同样只要一行代码,这样却更加自然一些。

所以分析到最后,如果想要完全接管@property,最好不要用@synthesize,但是当然你是可以使用@synthesize的,所以这也是@synthesize的一种情况,在这种情况下,@synthesize只有一个作用就是帮你生成ivar。

而且与@synthesize相对的@dynamic,就是让你动态的实现一个属性的访问方法和ivar,如果你想要完全接管其property,最好用@dynamic修饰property,虽然不是必要的,但是显示的声明可以让别人更容易看懂你的代码:你是自己实现的这个属性。

不推荐用来自定义变量名

@synthesize还可以用来自定义Property所对应的ivar的名称

假设有一个属性firstName

@synthesize firstName;


上述代码就会生成一个firstName的实例变量与firstName属性相对应。

@synthesize firstName = myFirstName;


该种方式则可以自定义Property所对应的实例变量名称

当然这种方式并不推荐,因为如果大家可能更多使用的是默认的方案,这样所有人写出的代码都更容易理解。

最好的用法:在protocol中声明属性

在protocol声明property,让实现这个协议的类共享一些属性,就像协议定义方法一样,目的是只提供一个统一接口的规范,而不给出具体的实现,属性也是相同,属性的实例变量也需要类来自己synthesize,而且编译器不会自动帮你生成,需要注意的是最好不要将Property放在@optional中,因为这样当你没有自己合成ivar时Xcode不会给你警告,而当你在访问这些属性时不会有问题,而当运行时会报 unrecognized selector sent to instance的异常,程序会崩溃。

有两种方式实现protocol中的属性,第一个是使用@synthesize,一句话就可以自动生成ivar和访问方法(当然你也可以重写setter和getter方法)。第二种方法是完全接手,自己声明实例变量(ivar的名称完全可以自己定义,他和属性的关联实际上是在访问方法中关联的),同时实现setter和getter方法(两个方法少一个编译器都会有警告)。总的来说两种方法都可以自定义实例变量名,第一种方法更简便且更清晰,同时只要重写自己需要的定制的访问方法,所以更推荐第一种方法。

重载属性时最好使用@dynamic

这是我在Xcode中重载一个属性时编译器给的警告,警告中很明显的告诉我们这种情况下应该使用@dynamic

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

那到底能不能用@synthesize呢?我们就试试呗

@interface ViewController : UIViewController

@property(nullable, nonatomic, readonly, copy) NSString *nibName;

@end

@implementation ViewController

@synthesize nibName = myNibName;

- (void)viewDidLoad {
[super viewDidLoad];
self.nibName = @"DaiPei";
NSLog(@"the ivar myNibName:%@", myNibName);
}

- (void)setNibName:(NSString * _Nullable)nibName {
myNibName = nibName;
}

- (NSString *)nibName {
return myNibName;
}

@end


新建一个工程,重载ViewController的一个叫nibName的属性(本来重载了其view属性,发现这个vc完全没有用了,连viewDidLoad方法都进不去,然后就挑了一个看似不是很重要的属性)

然后最后打印的结果是
the ivar myNibName:DaiPei
,说明重载成功了

那如果把setter和getter方法删去呢?结果是相同的

所以结论是@synthesize可以在重载时使用的,但是我觉得最好的方式还是使用@dynamic,毕竟这是苹果官方推荐的,@synthesize在这里总感觉不是那么优雅!

@synthesize可以强行改变readonly性质

有一个比较有趣的现象,在头文件中声明的只读property,可以重写其getter方法,而不需要使用@synthesize去生成实例变量,但如果是在.m中声明的property,重写其getter方法时,编译器就不会帮我们自动生成实例变量了。

虽然说.h文件是暴露给外面的一个文件,但在里面声明的readonly属性在类的内部也是无法修改的

如何在内部修改.h中有readonly修饰的属性,有三种方法:

直接修改property对应的ivar

重新在.m文件中声明该属性,并加上readwrite修饰

使用@synthesize,同时生成getter和setter方法(等于是强行使property属性变成了readwrite,我发现即使是在.m文件声明的属性也是可以的)

当然这种我这里只是提出@synthesize的这个性质,我并不推荐这种用法,我却觉得这种用法不好,这并不是@synthesize本应该做的事情,如果需要让一个属性在内外有不同表现,第二种方法应该是最好的,显示的表明这个属性的在内外有不同的表现。

勘误

在category中声明属性需要使用@synthesize

有些地方说@synthesize可以用在category中属性的实例变量的合成,我试了一下是不行的,会报错:@synthesize not allowed in a category’s implementation,我不知道以前是不是可以,我的环境是Xcode7,编译器版本:Apple LLVM version 7.3.0 (clang-703.0.29),在category中添加属性只能使用Associated Object来实现,还有一种不优雅的实现方式是用一个单例来保存这些实例遍历。

使用@dynamic时需要使用@synthesize

实际上@dynamic与@synthesize是相对的,也是用来修饰property的,表示实例变量的setter和getter方法手工实现或是在运行时生成。

总结

如果没有ivar的支持,属性单独是没有太多作用的,属性本身的作用我想是在于对实例变量在原子性、读写权限、内存管理、访问方法进行封装,并且声明(注意这里是声明)setter和getter方法(即使你没有实现这两个方法,都在代码里都可以调用这两个方法)。

当你在头文件或是类扩展里声明一个属性时,编译器会在编译期间自动插入一句@synthesize yourProperty = yourProperty;(Objective-C Autosynthesis of Properties,这是clang的支持的特性,实际上自动生成和手动生成效果是相同的)帮你生成一个以开头的同名的实例变量(需要注意的是,前面这句话是不对的,是我最开始的理解,后来我发现自动生成和手动生成有一点不一样,就是自动生成会根据你属性中的修饰词选择性的生成getter和setter方法,而@synthesize没有那么智能,会同时生成setter和getter方法),这句代码同时会按照你声明属性时给出的修饰符自动生成其setter、getter方法,需要注意的是@synthesize做的事情不仅是生成实例变量,还也会生成getter和setter的实现。

所以何时要使用@synthesize?其实很简单,就是在某些编译器无法自动帮你加上这句话的场景下,你自己不想亲自声明ivar实现访问方法时,使用此保留字帮你快捷实现。而实际上这个情况只有一个对于声明在protocol中的property。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐