如何摆脱“未声明的选择器”警告

Posted

技术标签:

【中文标题】如何摆脱“未声明的选择器”警告【英文标题】:How to get rid of the 'undeclared selector' warning 【发布时间】:2011-09-07 16:09:45 【问题描述】:

我想在 NSObject 实例上使用选择器 不需要实现的协议。例如,如果调用它的 NSObject 实例支持,则应该设置一个错误属性的类别方法。这是代码,代码按预期工作:

if ([self respondsToSelector:@selector(setError:)])

    [self performSelector:@selector(setError:) withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]];

但是,编译器没有看到任何带有 setError: 签名的方法,所以它给了我一个警告,每行包含@selector(setError:)sn-p:

Undeclared selector 'setError:'

我不想声明一个协议来消除这个警告,因为我不希望所有可能使用它的类来实现任何特殊的东西。按照惯例,我希望他们拥有setError: 方法或属性。

这可行吗?怎么样?

干杯, EP

【问题讨论】:

解决方案在performSelector may cause a leak because its selector is unknown中有很好的解释 不推荐使用的选择器将导致警告。访问选择器不再安全,因为选择器可能会在某个时候被删除。 【参考方案1】:

另一种选择是禁用警告:

#pragma GCC diagnostic ignored "-Wundeclared-selector"

您可以将此行放在出现警告的 .m 文件中。

更新:

它也适用于 LLVM,如下所示:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"

... your code here ...

#pragma clang diagnostic pop

【讨论】:

#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" // Do your thing #pragma clang diagnostic pop 是的,就像@dizy 所说的那样。 (抱歉回复晚了,但我错过了通知)。 我还需要#pragma clang diagnostic ignored "-Wselector" @mdorseif 大多数情况下,您“必须”排除的警告都列在编译日志中。您可以使用此概念使任何警告静音。很高兴您添加了有关选择器的内容。 @epologee 你可以通过构建设置“Undeclared Selector”来做同样的事情【参考方案2】:

看看NSSelectorFromString。

 SEL selector = NSSelectorFromString(@"setError:");
 if ([self respondsToSelector:selector])

它将允许您在运行时创建选择器,而不是在编译时通过 @selector 关键字创建,编译器将没有机会抱怨。

【讨论】:

嗨@sergio,您和@jacobrelkin 的答案都有效。几乎同时提交。如果有的话,你会帮我选择“更好”的答案吗? 我更喜欢这个答案,因为它看起来更像“可可”-y(?)。 sel_registerName() 东西看起来晦涩难懂,除非你知道自己在做什么,否则你不应该直接调用,有点像 obj_msg_send() ;) 不确定它是否是 Xcode 5,但我收到了不同的警告:“PerformSelector 可能会导致泄漏,因为它的选择器未知” @Hampden123:这是一个不同的问题。看看这里:***.com/questions/7017281/…【参考方案3】:

我认为这是因为某些奇怪的原因选择器没有在运行时注册。

尝试通过sel_registerName()注册选择器:

SEL setErrorSelector = sel_registerName("setError:");

if([self respondsToSelector:setErrorSelector]) 
   [self performSelector:setErrorSelector withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]];

【讨论】:

嗨@jacobrelkin,您和@sergio 的答案都有效。几乎同时提交。如果有的话,你会帮我选择“更好”的答案吗? @epologee NSSelectorFromString 无论如何都会在后台调用sel_registerName()。选择更适合您的。 @epologee 我认为直接调用sel_registerName() 可以更明确地说明您这样做的原因。 NSSelectorFromString 不会告诉你它将尝试注册选择器。 不确定它是否是 Xcode 5,但我收到了不同的警告:“PerformSelector 可能会导致泄漏,因为它的选择器未知” @Hampden123 你提到的是另一个警告。 What you need 可能是 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"【参考方案4】:

我通过使用该方法#include'ing 文件来消除该消息。该文件中没有使用任何其他内容。

【讨论】:

虽然这是不太优雅的解决方案,但它对我有用,因为我有可能收到选择器的“已知嫌疑人”。此外,如果我实现运行时选择器方法,我仍然会在 performSelector 语句中收到不同的警告;即,“PerformSelector 可能会因为它的选择器未知而导致泄漏”。所以谢谢! 投票最多的答案都不正确。 “未声明的选择器”警告的目的是在您更改所依赖的选择器的名称时在编译时捕获错误。所以#import声明你所依赖的方法的文件是最正确的。【参考方案5】:

我意识到我对此线程有点晚了,但为了完整起见,您可以使用目标构建设置全局关闭此警告。

在“Apple LLVM 警告 - Objective-C”部分中,更改:

Undeclared Selector - NO

【讨论】:

【参考方案6】:

如果您的类实现了 setError: 方法(甚至通过声明动态的最终错误属性的设置器),您可能希望在接口文件 (.h) 中声明它,或者如果您不想显示它您可以尝试使用 PrivateMethods 技巧:

@interface Yourclass (PrivateMethods)

- (void) yourMethod1;
- (void) yourMethod2;

@end

就在您的 @implementation 之前,这应该隐藏警告;)。

【讨论】:

谢谢,但我是从一个类别调用该方法,所以这不适用。干杯,EP。 我们中的一些人正在做一些更奇特的事情——在我的例子中,选择器是在 F# 对象中实现的。 这并没有摆脱XCode 7.1.1 / ios 9.1中的警告,我可以看到PerformSelector may cause a leak because its selector is unknown【参考方案7】:

一个非常舒适的宏,可以放入您的 .pchCommon.h 或任何您想要的位置:

#define SUPPRESS_UNDECLARED_SELECTOR_LEAK_WARNING(code)                        \
_Pragma("clang diagnostic push")                                        \
_Pragma("clang diagnostic ignored \"-Wundeclared-selector"\"")     \
code;                                                                   \
_Pragma("clang diagnostic pop")                                         \

这是对类似问题的this question 的编辑...

【讨论】:

【参考方案8】:

你可以像截图一样在 Xcode 中关闭它:

【讨论】:

不错的一个。不过,我更喜欢仅在明确的情况下禁用警告,通过说“在这种情况下clang 是错误的,我知道我在做什么”。感谢您的意见!【参考方案9】:

您也可以先将有问题的对象转换为 id 以避免警告:

if ([object respondsToSelector:@selector(myMethod)]) 
    [(id)object myMethod];

【讨论】:

这并没有消除关于 if 表达式内容的相同警告,一直到今天的 XC7.1。【参考方案10】:

避免此警告的另一种方法是确保您的选择器方法如下所示:

-(void) myMethod :(id) sender

如果您想接受任何发件人,请不要忘记“(id)发件人”,或者如果您愿意,请指定发件人对象的类型。

【讨论】:

【参考方案11】:

虽然正确的答案可能在于通过导入通知 Xcode 或注册选择器存在这样的选择器,但在我的情况下,我错过了一个分号。在“修复”错误之前,请确保错误是正确的,而您的代码不是。例如,我在 Apple 的 MVCNetworking 示例中发现了错误。

【讨论】:

不,正确的答案不是通过导入通知 Xcode,因为这些导入已经到位。正确答案是上面标记为...正确答案的答案,尽管@sergio 的答案也可以解决问题。使用 wrong 选择器不是这个问题的主题,因此更改选择器不是答案。不过,我会保留你的反对票。 感谢您提醒我,我可能应该使用评论。我只能说缺少导入也会导致这个 Xcode 警告,如果不是这个特定的实例的话。在运行时构建选择器或以动态方式响应方法调用(例如 methodSignatureForSelector)时,我只会推荐 NSSelectorFromString 或其他此类“注册”选项。注册它意味着您正在“解决错误”,因此在某些情况下是不正确的,因为更正确的方法是修复警告(如果 clang 分析是正确的,那就是。) 事实上,我现在看到原始问题清楚地说,“不需要实施协议”——根本没有提到导入。所以我会提出导入类别本身可能是该用户的最佳选择。从技术上讲,这里的任何其他内容都可以定义选择器两次。是的? -- 编辑:啊,我走得太远了。感谢您的回复,我现在就停下来。 :)【参考方案12】:

我能够通过添加 nothing 方法来消除警告(披露:我没有想到这一点,但通过谷歌搜索 scheduletimerwithtimeinterval 找到了它)

    [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
                                     target:self
                                   selector:@selector(donothingatall:)
                                   userInfo:nil
                                    repeats:YES];


    [[NSRunLoop currentRunLoop] run];

    HTTPLogVerbose(@"%@: BonjourThread: Aborted", THIS_FILE);

    


+ (void) donothingatall:(NSTimer *)timer



虽然我很高兴知道如何隐藏警告,但修复它会更好,而且 Sergio 和 Relkin 的技术对我都不起作用,原因不明。

【讨论】:

如果其他人阅读了这个可行的解决方案,他/她会很困惑,包括你未来的自己。如果您确定通过调用不存在的选择器知道自己在做什么,从而导致警告,请跳过误导性方法存根并确保您的代码表达了您的意图。 好点。我正在处理继承的代码,只是想弄清楚如何让警告消失,而不是试图解决为什么选择器不存在的基本问题。一步一步,我总是说。

以上是关于如何摆脱“未声明的选择器”警告的主要内容,如果未能解决你的问题,请参考以下文章

警告为错误 - 如何摆脱这些

在 iOS 7 中使用 UIScrollView 在 iOS 中创建水平滚动 UIButton

如何摆脱 PHP 中的 filesize() 警告?

如何摆脱增量注释处理请求的警告?

Flickr 照片管理器中的 JSON 警告

如何摆脱烦人的 Horizo​​ntalContentAlignment 绑定警告?