这个Objective-C属性综合警告是什么意思?

17

自从升级到Xcode 5.1以后,我的项目中的某些代码开始出现以下警告。我正在试图弄清它的含义。

警告:自动属性综合将不会综合属性“responseHeader”,因为它是“可读写”的,但是它将通过另一个属性综合“只读”

出现警告的.m文件中的代码:

@interface S3Response ()
@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
@end

在.h文件中,该属性的先前声明:

@property (nonatomic, readonly) NSDictionary *responseHeader;

该属性没有 @synthesize 语句,并且 responseHeadersetResponseHeader 也没有被定义为方法。但是,有一个名为 responseHeader 的显式 ivar 定义。

对我来说似乎很简单:该属性被声明为类的用户只读,但在本地可读写以便类可以设置它。

这个警告是什么意思?我应该怎么做?


尝试将头文件定义更改为(nonatomic, readonly, retain) - Kevin
那并没有解决警告。也没有帮助我理解警告的含义。 :) - dpassage
你正在继承哪个类?那个类有一个 responseHeader 属性吗? - Kevin
@JoshCaswell,不是的。修改了问题以澄清。 - dpassage
@Kevin,它是NSObject的子类。然而,我发现一个名为responseHeader的实例变量的显式声明;已经修改了问题。 - dpassage
看这张截图。点击“在这里声明的属性”。它会突出显示在哪里? - Kevin
2个回答

23

这段代码似乎来自于AWS SDK for iOS, 而S3ResponseAmazonServiceResponse的一个子类。

AmazonServiceResponse公共接口定义了只读属性。

@interface AmazonServiceResponse:NSObject
// ...
@property (nonatomic, readonly) NSDictionary *responseHeader;
@end

在实现文件中的类扩展中,该变量被重新定义为可读写。

@interface AmazonServiceResponse ()
@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
@end

现在子类S3Response也希望对这个属性进行读写访问,因此它也在其实现文件的类扩展中进行定义:
@interface S3Response ()
@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
@end

编译器报错是因为编译"S3Response.m"时不知道在超类中存在一个属性的setter(此时它不读取超类的实现文件)。 此外,编译器不能在子类中简单地合成一个setter,因为它无法知道该属性在超类中由一个实例变量支持。
但是您知道将生成setter,因此可以通过向子类实现添加@dynamic声明来消除警告。
@implementation S3Response
@dynamic responseHeader;
...

@dynamic是对编译器的“承诺”,保证在运行时所有必要的访问器方法都将可用。


果然,这解决了问题。加分是因为你准确地找出了我所说的代码 :) 不过,这个警告信息还是相当糟糕的。 - dpassage
在Xcode6中,它不起作用,你需要遵循这个步骤:https://dev59.com/bWEh5IYBdhLWcg3wdjTt - LiangWang
@Jacky:你能澄清一下你的说法吗?我刚刚用Xcode 6 beta 4和AWS SDK for iOS v1.7.1进行了验证,发现我的建议仍然可以解决编译器警告。在你提供的问题的答案中也建议添加“@dynamic ...”。- 感谢您的反馈! - Martin R

-1
这里的问题如下。
默认情况下,如果不明确写出所有权(weak/retain/strong/assign),xCode会自动检查类型。因此,在NSDictionary的情况下,它将是strong。因此,在接口中,您将拥有
@property (nonatomic, readonly, strong) NSDictionary *responseHeader;

那么它将与您的私有实现定义相矛盾

@property (nonatomic, readwrite, retain) NSDictionary *responseHeader;

编译器在属性合成时不匹配强引用和保留引用,尽管它们在形式上是相同的。

为了解决这种情况,您可以在两种情况下都写入retain,或者更正确的做法是根本不写retain。在两个定义中,默认情况下都是强引用。


1
“strong”和“retain”是等效的,因此如果这是真的,应该被视为一个错误。 (尽管编译器对不匹配的警告可能是恰当的,但这有点学究气。) - jscs
1
从所有权的角度来看,这是正确的。但似乎由于某些自动机制的原因,ARC会将它们区分开来。 - malex
“strong” 和 “retain” 是完全的同义词,可以混用而不会导致任何警告。 - Martin R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接