Auto property synthesis will not synthesize property …because it is ‘readwrite’ but it will be synth

本文介绍如何使用MJExtension解析JSON时解决关键字冲突的问题。当服务器返回的数据中包含Objective-C的关键字时,MJExtension将无法正常解析。文章提供了一种解决方法,通过调整模型属性名称来避免这一问题。

                                                                                  

使用Json解析框架MJExtension,如果服务器传来的字典key,是oc中的关键词,则会报错。


而MJExtension要求是模型里的属性名要与数组的key一致。

则需要如下更改。


                                                         


                                                       

<think> 我们正在处理一个关于Objective-C属性合成的编译警告/错误。错误信息明确指出:由于属性'maxRecordCount'被声明为'readwrite',但将通过另一个属性被合成为'readonly',因此编译器不会自动合成该属性。 根据引用[2]中的类似问题(关于'description'属性),我们可以推断: 1. 问题原因:在子类中声明了一个与父类中同名且属性特性(特别是读写性)冲突的属性。父类中已经存在一个名为'maxRecordCount'的只读属性,而我们在子类中试图将其重新声明为可读写。编译器在自动合成属性时发现这种不一致,因此报错。 2. 解决方案:在子类的实现文件中使用`@dynamic maxRecordCount;`来告诉编译器不要自动合成该属性的存取方法,而由开发者自己提供或者在运行时提供(例如通过运行时机制或者父类的方法)。 但是,我们需要注意的是,引用[2]中解决的是'description'属性,这是一个在NSObject中已经存在的只读属性。同样,我们的'maxRecordCount'属性很可能也是在某个父类中已经定义为只读。 具体步骤: 步骤1:确认父类中是否已经存在一个名为'maxRecordCount'的只读属性。 步骤2:在子类的实现文件(.m)中,使用`@dynamic maxRecordCount;`来避免自动合成。 然而,我们还需要考虑是否真的需要覆盖父类的只读属性为可读写。如果确实需要,那么除了使用`@dynamic`之外,我们还需要手动提供setter方法(因为父类只有getter,没有setter)。如果我们不需要写,那么可以保持为只读,或者重新考虑设计。 因此,完整的解决方案可能包括: 选项1:如果不需要写该属性,则将其声明为只读(readonly)以与父类一致。 选项2:如果需要写,则在子类中: a. 在.h文件中声明属性为readwrite(如当前所做)。 b. 在.m文件中使用`@dynamic maxRecordCount;`,然后自己实现setter方法(如果父类没有setter,则必须自己实现)。 由于错误信息提示我们将通过另一个属性合成'readonly',这意味着父类中已经有一个同名的只读属性,因此我们无法通过自动合成来生成setter。所以,如果我们确实需要setter,就必须自己写。 示例代码: 假设父类(ParentClass)中有一个只读属性: ```objective-c @property (nonatomic, assign, readonly) NSInteger maxRecordCount; ``` 子类(ChildClass)中我们想要可读写: 在ChildClass.h中: ```objective-c @interface ChildClass : ParentClass @property (nonatomic, assign, readwrite) NSInteger maxRecordCount; @end ``` 在ChildClass.m中: ```objective-c @implementation ChildClass @dynamic maxRecordCount; // 避免自动合成,防止编译错误 // 然后我们需要自己实现setter - (void)setMaxRecordCount:(NSInteger)maxRecordCount { // 这里我们可以使用实例变量来存储,但是注意父类中已经有一个同名的只读属性,我们可能无法直接访问其背后的实例变量(如果父类没有提供的话)。 // 所以,我们可能需要自己声明一个实例变量,例如: // _maxRecordCount = maxRecordCount; // 这需要我们在子类中声明一个实例变量,或者使用关联对象等。 // 但是,更好的做法是:如果我们知道父类是如何存储的,并且父类提供了设置方法(比如通过内部方法或者KVC),我们可以使用那些方法。 // 如果父类没有提供,我们可能需要考虑其他设计。 // 因此,这里的具体实现取决于父类的实现细节。 // 一种常见做法是使用关联对象: // 首先引入<objc/runtime.h> // 然后: objc_setAssociatedObject(self, @selector(maxRecordCount), @(maxRecordCount), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } // 同时,我们还需要重写getter,因为使用了关联对象,或者如果我们不想使用父类的getter(因为父类返回的是它自己的值,而我们希望返回子类设置的值),那么: - (NSInteger)maxRecordCount { return [objc_getAssociatedObject(self, @selector(maxRecordCount)) integerValue]; } ``` 但是,使用关联对象可能不是最佳实践,因为它破坏了封装性。更好的方法是与父类的设计者沟通,或者重新审视是否真的需要覆盖父类的只读属性。 因此,在实际开发中,我们更倾向于避免与父类属性重名。如果可能,考虑更换属性名。 总结解决方案: 1. 更换属性名(推荐):避免与父类属性冲突。例如,使用`myMaxRecordCount`。 2. 如果必须使用相同名称,并且需要可写: a. 在子类中声明为`@dynamic`。 b. 手动实现setter(和getter,如果需要的话)方法。存储方式可以选择使用关联对象、子类自己的实例变量等,但要小心与父类的实现冲突。 根据引用[2]中的经验,直接使用`@dynamic`可以消除编译错误,但如果没有提供setter方法,那么在设置属性时会导致崩溃(因为找不到setter方法)。所以,如果我们需要设置这个属性,就必须自己实现setter。 因此,请根据实际需求选择方案。如果不需要写,那么将子类中的属性改为`readonly`即可。如果需要写,则按照上述步骤手动实现存取方法。 注意:在引用[2]中,他们只是使用了`@dynamic`而没有实现setter,那是因为在那种情况下(`description`属性),可能并不需要设置(或者通过其他方式设置,比如父类的内部机制)。但对于我们自己的属性,如果我们设置了`@dynamic`,就必须确保在运行时能够处理该属性的存取,否则程序运行时会崩溃。 最后,建议检查父类中是否已经存在该属性,并考虑是否有必要重写。如果父类的属性已经满足需求,则无需在子类中重新声明。 </think>### 解决属性合成冲突:'maxRecordCount'的读写性冲突 在Objective-C开发中,当子类声明与父类同名的属性且读写性冲突时,会出现`Auto property synthesis will not synthesize property 'X' because it is 'readwrite' but it will be synthesized 'readonly'`错误。以下是具体解决方案: #### 原因分析 1. **父类存在同名只读属性** 父类已声明`@property (nonatomic, readonly) NSInteger maxRecordCount;`,子类重新声明为`@property (nonatomic, readwrite) NSInteger maxRecordCount;` 2. **编译器无法协调冲突** 编译器无法决定应继承父类的`readonly`实现还是为子类新建`readwrite`实现 #### 解决方案 ##### ✅ 推荐方案:使用`@dynamic`显式声明 ```objective-c // MySubClass.h @interface MySubClass : ParentClass @property (nonatomic, readwrite) NSInteger maxRecordCount; // 重写为可读写 @end // MySubClass.m @implementation MySubClass @dynamic maxRecordCount; // 关键声明 // 手动实现setter方法 - (void)setMaxRecordCount:(NSInteger)maxRecordCount { // 实现自定义存储逻辑 // 例如使用关联对象: objc_setAssociatedObject(self, @selector(maxRecordCount), @(maxRecordCount), OBJC_ASSOCIATION_RETAIN); } // 手动实现getter方法 - (NSInteger)maxRecordCount { return [objc_getAssociatedObject(self, @selector(maxRecordCount)) integerValue]; } @end ``` ##### ⚠️ 备选方案:修改属性名(避免冲突) ```objective-c // 推荐新属性名 @property (nonatomic) NSInteger customMaxRecordCount; ``` #### 关键说明 1. **`@dynamic`的作用** 显式告知编译器不自动生成存取方法,需开发者手动实现 2. **必须实现存取方法** 若未实现setter/getter,运行时会触发`unrecognized selector`崩溃 3. **存储方案选择**: - 关联对象(如示例) - 子类新增实例变量(需`@synthesize customVar = _customVar`) - KVC存储(`setValue:forKey:`) #### 最佳实践建议 1. **优先重命名属性** 冲突属性名通常暗示设计缺陷,建议使用`custom`/`my`前缀 2. **检查父类声明** 使用Cmd+点击查看属性原始定义 3. **避免系统保留名** 如`description`/`hash`等NSObject保留属性名[^1][^2] > 当无法修改属性名时,`@dynamic`+手动实现存取方法是唯一可靠方案。此模式在覆盖系统类(如NSDictionary/NSArray)属性时尤其常见[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值