OC 中 覆盖父类属性会有Auto property synthesis will not synthesize property 'xxx'的警告
来源:神经骚栋     阅读:986
寻找程序员
发布于 2018-09-28 23:25
查看主页


情景复原


今天无意间弄了一个警告. 警告就会存在着肯定的隐藏风险,所以就肯定要处理这种异常风险,接下来我们看一下当时的情景代码.

我首先写了一个名为BaseObject的基类 ,基类中具备一个遵循BaseObjectDelegate协议的代理商属性对象delegate,如下所示

#import <Foundation/Foundation.h>@protocol BaseObjectDelegate<NSObject>- (void)baseObjectDeleagateAction;@end@interface BaseObject : NSObject@property(nonatomic,weak)id <BaseObjectDelegate>delegate;@end

而后,我写了一个继承于BaseObject的子类 SubObject, SubObject中具备一个遵循SubObjectDelegate协议的代理商属性对象delegate,代码如下所示.

#import "BaseObject.h"@protocol SubObjectDelegate<BaseObjectDelegate,NSObject>- (void)subObjectDeleagateAction;@end@interface SubObject : BaseObject@property(nonatomic,weak)id <SubObjectDelegate>delegate;@end

这时候,子类SubObject就会报警告.截图如下所示.

文字错误: Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its superclass, use @dynamic to acknowledge intention

这种情况就相似于UIScollView和子类UITableView的关系,两者都还有遵循不同协议的delegate属性,但是并没有警告产生.所以这个警告我们要好好研究一下.


处理方案


我们先说说怎样来处理这个警告,而后我们再来聊一下这个警告是如何产生的以及有什么安全隐患.

首先,我们不会去屏蔽这种警告,那么怎样办呢?最简单的方式就是把子类的delegate 改成别的名称,例如subDelegate,这样子类就会有两个代理商属性,一个是继承于父类的,一个是自己定义的.代码如下所示.

@interface SubObject : BaseObject@property(nonatomic,weak)id <SubObjectDelegate>subDelegate;@end

还有一种处理方案就是使用@synthesize关键词.我们在.m文件中编写如下代码就可处理警告.

#import "SubObject.h"@implementation SubObject@synthesize delegate = _delegate;@end


警告分析


下面我们就来分析一下警告产生过程以及警告会有什么样的安全隐患.我查阅了网上了很多前人所写的博客,这里只是做了一下记录,并非自己验证过的结果.所以要注意.

要理解这个警告,我们就要理解什么是属性,在OC中属性的定义就是给一个类的成员变量提供了封装,关键字是@property.

Objective-C properties offer a way to define the information that a class is intended to encapsulate。

通过公告属性,我们可以很简单的为一个成员变量定义其能否是只读的还是读写的,能否是原子操作的等等特性,也就是说假如说封装是为成员变量套了一层壳的话,那么 @property关键字做的事情就是预约义这层壳是个什么样子的壳,而后通过 @sythesize关键字生成真正的壳并把这个壳套在实际的成员变量上(假如没有定义这个成员变量该关键字也可以自动生成对应的成员变量)。当然这层壳包括了自动生成的get set 方法。

但是如同现在的开发人员对@sythesize的使用频率很低了,那么@sythesize究竟有什么作用呢?在最开始的时候,我们在代码中写了@property对应的就要写一个@sythesize,在苹果使用了LLVM (2005年Swift之父Chris Lattner将苹果使用的 GCC 全面转为 LLVM)作为编译器以后,假如我们没有写 @sythesize,编译器就会为我们自动的生成一个 @sythesize property = _property。这个特性叫做Auto property synthesize

说了这么多,现在我们来回头看看问题的关键,当我们想覆盖父类的属性并做少量修改的时候,Auto property synthesize这个特性就有点不知道该干嘛了,这个时候他选择不跑出来为我们干活,所以编译器就不会自动生成@sythesize property = _property,但是子类总得有个壳啊,人家都有@property了,怎样办?直接拿过来父类的壳复制一份不论三七二十一套在子类的成员变量身上。注意,有些情况下这会产生运行时的crash,比方:

一个父类 A

@interface A : NSObject@property(strong,nonatomic,readonly)NSString *name;@end

子类Aa

@interface Aa : A@property(strong,nonatomic,readwrite)NSString *name;@end

这种情况下编译器会给出 warning:

Auto property synthesis will not synthesize property 'name' because it is 'readwrite' but it will be synthesized 'readonly' via another property

注意,尽管只给出了 warning,但是这个时候显然 Aa 中是不会自动生成 set 方法的,假如在代码中调用了 Aa 的实例对象的 set 方法,运行时就会 crash,crash 起因是:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Aa setName:]: unrecognized selector sent to instance

所以遇到这个问题怎样处理?在子类中显式的公告一个@synthesize name = _name;就好,这样子类就会如愿的产生他的壳,编译器也不纠结了,就去掉了 warning,这样问题就处理了.


问题总结


这个问题归根究竟是由于Auto property synthesize不工作,导致子类属性直接把父类属性的修饰属性复制到自己身上,这样就会产生安全隐患,最终生成警告. 所以我们要自己写一个显式的公告 @synthesize name = _name; 就可处理问题.

参考原文链接


免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 系统环境 服务器应用
相关推荐
APUE读书笔记-05标准输入输出库(4)
iOS 12.2测试版有这么几个功能 可能会出现在正式版
CocoaPods实现板块化开发
数据库覆盖式数据导入方法:部分和完全
请H5大神指路
首页
搜索
订单
购物车
我的