【问题标题】: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

【问题讨论】:

标签: objective-c selector categories


【解决方案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:这是一个不同的问题。看看这里:stackoverflow.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 的技术对我都不起作用,原因不明。

        【讨论】:

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