如何摆脱“未声明的选择器”警告
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 的答案都有效。几乎同时提交。如果有的话,你会帮我选择“更好”的答案吗? @epologeeNSSelectorFromString
无论如何都会在后台调用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】:
一个非常舒适的宏,可以放入您的 .pch
或 Common.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 的技术对我都不起作用,原因不明。
【讨论】:
如果其他人阅读了这个可行的解决方案,他/她会很困惑,包括你未来的自己。如果您确定通过调用不存在的选择器知道自己在做什么,从而导致警告,请跳过误导性方法存根并确保您的代码表达了您的意图。 好点。我正在处理继承的代码,只是想弄清楚如何让警告消失,而不是试图解决为什么选择器不存在的基本问题。一步一步,我总是说。以上是关于如何摆脱“未声明的选择器”警告的主要内容,如果未能解决你的问题,请参考以下文章