语义问题:属性的合成吸气剂遵循可可命名约定返回“拥有的”对象


283

我目前正在使用iOS 5 SDK尝试开发我的应用。我正在尝试将NSString设置为属性,然后在.m文件中对其进行合成(我之前做过但没有任何问题)。现在,我遇到了这样一个问题:“语义问题:属性的合成吸气剂遵循可可命名约定来返回“拥有的”对象。”

这是我的代码:.h

@interface ViewController : UIViewController {
     NSString *newTitle;
}
@property (strong, nonatomic) NSString *newTitle;

.m

@synthesize newTitle;

有人知道我该如何解决吗?谢谢!!


我遇到了一个非常类似的错误:“属性遵循可可命名约定来返回“拥有的”对象”,Bavarious的回答似乎也可以解决此问题。
TMin

Answers:


606

我的猜测是,您使用的编译器版本也遵循声明属性的内存管理规则 -更具体地说,声明属性的访问器:

如果使用名称以“ alloc”,“ new”,“ copy”或“ mutableCopy”开头的方法创建对象,则将拥有该对象的所有权。

名为的属性newTitle在综合后会产生称为的方法-newTitle,因此产生警告/错误。-newTitle本来应该是该newTitle属性的getter方法,但是命名约定规定,以其名称开头的方法会new返回调用者拥有的对象,而getter方法并非如此。

您可以通过以下方法解决此问题:

  1. 重命名该属性:

    @property (strong, nonatomic) NSString *theNewTitle;
  2. 保留属性名称并指定一个不以特殊方法名称前缀之一开头的getter名称:

    @property (strong, nonatomic, getter=theNewTitle) NSString *newTitle;
  3. 保留属性名称和getter名称,并告诉编译器,即使getter名称以开头new,它也属于none方法族,而不是new方法族:

    #ifndef __has_attribute
    #define __has_attribute(x) 0  // Compatibility with non-clang compilers
    #endif
    
    #if __has_attribute(objc_method_family)
    #define BV_OBJC_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
    #else
    #define BV_OBJC_METHOD_FAMILY_NONE
    #endif
    
    @interface ViewController : UIViewController
    @property (strong, nonatomic) NSString *newTitle;
    - (NSString *)newTitle BV_OBJC_METHOD_FAMILY_NONE;
    @end
    

    请注意,即使此解决方案允许您同时保留newTitle属性名称和getter名称,但使用一个-newTitle不返回调用方拥有的对象的方法可能会使其他人混淆您的代码。


作为记录,Apple已发布《过渡到ARC发行说明》,其中指出:

您不能给属性以new或开头的名称copy

他们已经被告知他们的声明不够准确:罪魁祸首是吸气剂方法名称,而不是属性名称。


2015年1月17日,编辑:我刚刚注意到最近对Clang所做的一项承诺,建议objc_method_family(none)在属性名称与特殊方法族前缀之一匹配的一般情况下(使用)对上述选项3(使用进行修复)。Xcode最终可能会合并此更改。


6
像一个有魅力的人一样工作!!谢谢!!!供将来参考-我使用了“ @property(强,非原子,getter = theNewTitle)NSString * newTitle;”
Noam

8
很棒的答案。我有以“ new”开头的变量。

我也遇到了这个问题,这浪费了我很多时间!你真是个天才〜谢谢!
H Lai

NS_RETURNS_NOT_RETAINED也是您需要的。
DawnSong

55

不可接受的对象名称

  • newButton
  • copyLabel
  • allocTitle

可接受的对象名称

  • neueButton
  • mCopyLabel
  • _allocTitle

#arc#自动合成的#xcode-4.6.1

**编辑**

显然,您也不能使用mutableCopy


1
我还注意到,“复制”目前无法使用。
Rishab

30

以new开头的成员的名称将触发警告。将名称更改为editedTitle,警告将消失。我找不到可以证实这一点的文档,但是通过测试,可以确定以“ new”开头的成员变量会加剧编译器。


8

ARC不允许在属性名称中使用“ New ....”。但是您可以通过更改getter名称来使用“ newTitle”。

@property (nonatomic, strong, getter=theNewTitle) NSString *newTitle;

6

看起来Bavarious所暗示的并不是您想要做的。您要做的就是声明一个实例变量NewTitle,然后合成该属性。我们曾经不得不声明实例变量和属性。不再。

现在,我相信正确的方法如下:

。H

@interface ViewController : UIViewController

@property (nonatomic, strong) NSString *newTitle;

.m

@synthesize newTitle = _newTitle; // Use instance variable _newTitle for storage

该属性的实例变量newTitle已综合。您不希望实例变量与属性相同- 太容易出错

请参见示例:声明属性和合成访问器


这取决于编译器版本。在这种情况下,最新版本的clang会发出警告,这就是为什么我在回答中提到编译器版本的原因。

我认为您没有解决问题。对于Xcode 9,这是一个错误,而不是警告。NS_RETURNS_NOT_RETAINED是您所需要的。
DawnSong

4

在CoreData中,如果在属性中使用“ new ...”(正常编译),它将随机崩溃,并带有“访问错误”异常。

没有崩溃日志,显示“所有异常断点”的行将完全没有帮助。



1

除了您应该/不能在属性名称前使用“ new”的问题之外,再说一件事:尽量避免在名称前使用“ new”。“新”取决于时间。当前它对您来说是新的,但是一段时间之后,您可能想再次实现一些新功能。因此,在名称中使用“ new”总是不好的。尝试这样思考:在编程世界中,“新”总是在创建某种东西:某种东西的新实例。

在您的情况下,当您要分配其他标题时,则将当前名称分配给属性titleReplacement。

还有一件事:尝试首先用动词命名函数和方法,例如setSomething或getSomething。但是在属性中,请尝试首先命名对象,例如heightMinimum,heightMaximum等。->在编码时使用检查器时,总是会寻找对象。试试看。;-)


1

NS_RETURNS_NOT_RETAINED 用于解决命名问题。

@property (nonatomic, copy) NSString *newTitle NS_RETURNS_NOT_RETAINED;

我们可以找到它的定义如下,

#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))

“ ns_returns_not_retained”属性是“ ns_returns_retained”的补充。如果函数或方法似乎遵循Cocoa约定并返回保留的Cocoa对象,则此属性可用于指示返回的对象引用不应被视为返回给调用方的“拥有”引用。Foundation框架定义了一个宏NS_RETURNS_NOT_RETAINED,该宏在功能上等效于以下所示的宏。

在此处附上更多详细信息


-2

尝试这个:-

@property (nonatomic,retain) NSString *newTitle;

1
尽管如此,同样的问题。仅供参考,错误行在@synthesize行上。
诺姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.