【问题标题】:Compiler gives warning on performSelectorOnMainThread:@selector(delegateMethod)编译器在 performSelectorOnMainThread:@selector(delegateMethod) 上给出警告
【发布时间】:2010-12-21 12:41:18
【问题描述】:

我有一个封装了一些网络服务功能的 NSOperation。 NSOperation 有一个委托,该委托将在操作结束时收到消息。

由于 NSOperation 存在于不同的线程上,我必须像这样进行调用:

[delegate performSelectorOnMainThread:@selector(getDealersIDSuccess:) withObject:result waitUntilDone:YES];

它工作得很好,但它给了我一个警告:

警告: '-performSelectorOnMainThread:withObject:waitUntilDone:' 在协议中找不到

我完全同意这个编译器,它看到了一个委托,它检查了协议,它没有发现 performSelector 方法的声明。

我的问题是:我可以通过以不同的方式进行此调用来消除警告吗?

我的两个猜测是我可以 (1) 编写一个名为

的方法
- (void) callDelegateMethodOnMainThred {
    [delegate getDealersIDSuccess:result]
}

并通过 performSelectorOnMainThread 调用它,但我发现该解决方案很麻烦,而且在委托之上需要额外的、难以阅读的步骤。

第二种解决方案可能是将委托转换为选择器内我的父对象的类型,但这简直太疯狂了,并且违背了委托封装模式。

我非常感谢对语言有更好理解的人提供的第三种解决方案:)

提前谢谢你。

编辑:添加委托声明:

id <ISDealersIDDelegate> delegate;

我将我的代表声明为 id。它自己扩展 UIViewController 的委托。

我可以看到将其声明为 NSObject 会起作用。

【问题讨论】:

  • 你的委托是如何声明的?
  • 所有 NSObjects 都应该响应 performSelectorOnMainThread:... 你的委托/你如何声明它/等等有问题...我们可以看看更多的代码吗?

标签: iphone objective-c


【解决方案1】:

performSelectorOnMainThread:withObject:waitUntilDone: 方法在NSObject 类中声明。如果您的委托对象继承自 NSObject,您可以将其声明为

NSObject<MyDelegateProtocol> *delegate;

因此编译器会知道委托响应 NSObject 的方法并且不会发出警告。

【讨论】:

  • +1 为正确答案。 &lt;NSObject&gt; 协议仅声明 performSelector:(和朋友)。您需要明确要求您的委托是实现您的委托协议的NSObject*
  • 感谢弗拉基米尔,您的回答完美无缺。起初,我犹豫将委托转换为 NSObject 而不是通用 ID。然后我恍然大悟,所有的对象都继承自 NSObject。
  • 即使你的自定义协议继承自 NSObject 协议,如果委托被声明为 'id' 而不是 'NSObject*',你仍然会收到此警告。也许有问题的方法被定义为 NSObject 类的实例方法,而不是 NSObject 协议的实例方法?
【解决方案2】:

在委托或其他协议实现上不调用 performSelectorOnMainThread: 可能是更好的解决方案。 让委托/接收者负责确定它是否需要在主线程上做事。

[delegate performSelector:@selector(delegateAction:)
               withObject:actionData];

委托实施

- (void)delegateAction:(NSData*)actionData
{
    [self performSelectorOnMainThread:@selector(updateUIForAction:)
                           withObject:actionData
                        waitUntilDone:NO];
}

- (void)updateUIForAction:(NSData*)actionData
{
    // Update your UI objects here
}

它可能看起来像更多代码,但现在责任在正确的地方

【讨论】:

    【解决方案3】:

    实际上,在 iOS 4 上,我更喜欢使用 NSNotifications 和 Observers(带有块)在主线程上执行更新。

    - (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block
    

    我写下了我的设计here

    【讨论】:

    • 谢谢 Henrik,我喜欢你的方法,在过去的几个月里我刚刚构建了一个完整的 Web 代理,所以还不喜欢离开这种方法。
    【解决方案4】:

    1) 在 .h 文件中声明您的代理协议以扩展 NSObject 协议

    @protocol YourDelegateProtocol <NSObject>
    

    2) 在您的调用中强制转换为 NSObject

    [(NSObject*)delegate performSelectorOnMainThread:@selector(getDealersIDSuccess:) withObject:result waitUntilDone:YES];
    

    我绝对推荐数字 (1)。

    【讨论】:

    • 这个我喜欢,特别是易于实现和可读性:)
    • 嗨,Dean,您的回答似乎是正确的,但尝试后警告仍然存在(第 1 次)。
    • 在这种情况下,NSObject 协议不包含该方法——它只存在于 NSObject 类本身中。对不起! (2)应该仍然有效(尽管我认为我更喜欢接受的答案!)
    • 是的,有道理,NSObject 协议只定义了 performSelector 方法,没有定义 performSelectorOnMainThread 方法。我选择了 Vladimir 解决方案,警告消失了,我了解了它为什么存在以及更多关于 NSObject 的信息。
    猜你喜欢
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    相关资源
    最近更新 更多