【问题标题】:How to use native C types with performSelectorOnMainThread:?如何将本机 C 类型与 performSelectorOnMainThread 一起使用:?
【发布时间】:2009-09-16 13:50:26
【问题描述】:

我想使用performSelectorOnMainThread: 致电(void)setDoubleValue:(double)value。

我认为可行的是:

NSNumber *progress = [NSNumber numberWithDouble:50.0];
[progressIndicator performSelectorOnMainThread:@selector(setDoubleValue:)
                                    withObject:progress
                                 waitUntilDone:NO];

没用。

然后我实现了一个辅助方法:

- (void)updateProgressIndicator:(NSNumber *)progress
{
    [progressIndicator setDoubleValue:[progress doubleValue]];
}

有效,但不是很干净。

之后我用NSInvocation尝试了它。

NSInvocation *setDoubleInvocation;;
SEL selector = @selector(setDoubleValue:);
NSMethodSignature *signature;
signature = [progressIndicator methodSignatureForSelector:selector];
setDoubleInvocation = [NSInvocation invocationWithMethodSignature:signature];
[setDoubleInvocation setSelector:selector];
[setDoubleInvocation setTarget:progressIndicator];

double progress = 50.0;
[setDoubleInvocation setArgument:&progress atIndex:2];

[setDoubleInvocation performSelectorOnMainThread:@selector(invoke)
                                      withObject:nil
                                   waitUntilDone:NO];

此解决方案有效,但它使用大量代码并且速度很慢。 (即使我存储了调用。)

还有其他方法吗?

【问题讨论】:

  • [[progressIndicator class] instanceMethodSignatureForSelector:selector]可以写成[progressIndicator methodSignatureForSelector:selector]

标签: objective-c cocoa multithreading


【解决方案1】:

如果您使用的是 Snow Leopard,则可以使用 Blocks:

dispatch_async(dispatch_get_main_queue(), ^{
    [progressIndicator setDoubleValue: 50.0];
});

【讨论】:

  • 这里还在 PPC 上……该死。无论如何,对于这么小的更改,该操作不会太耗费资源吗?
  • 不——比 -performSelectorOnMainThread: 的开销要少得多。无需装箱,调度队列的重量极轻。
  • 是否有可能必须等待其他操作完成才能运行此操作?这对于 ui 更新可能是致命的。
  • 主队列是串行的,因此您必须等待主队列中的其他项目运行。但同样适用于 -performSelector: 和其他机制。
  • dispatch_sync 是否类似于拥有...waitUntilDone:YES?
【解决方案2】:

您需要编写一个自定义的拆箱方法来包装 setDoubleValue:。

- (void) setDoubleValueAsNumber: (NSNumber *) number {
   [self setDoubleValue: [number doubleValue]];
}

【讨论】:

  • 但有必要。 -performSelector*:不进行自动装箱。
【解决方案3】:

Dave Dribin 有一个solution for this,它采用 NSObject 上的类别的形式。他的类别将方法调用包装在 NSInvocation 中并在主线程上调用它。这样,您可以使用任何您喜欢的方法接口,包括参数的原始类型。

Amber framework 在 NSObject 上也有一个类别,它添加了一个主线程代理,发送到该代理的任何消息都在主线程上执行。

【讨论】:

    【解决方案4】:

    这篇博文:http://www.cimgf.com/2008/03/01/does-objective-c-perform-autoboxing-on-primitives/ 指出,虽然 Cocoa 不会自动装箱原语,但它会自动将它们拆箱。所以数字和 BOOL 至少可以作为 NSNumber 类传入,被调用的函数会自动拆箱。我一直在使用代理对象(Uli 的 UKMainThreadProxy*),它工作得很好,尽管我确信它像其他任何东西一样有它的限制。

    【讨论】:

    • 该博客的作者在他的第一行写道:这篇文章不准确。 其次是作者在写这篇文章时抽了crack之类的东西,但没有从那以后就能够复制他的测试。由于历史原因,这篇文章留在这里。您确定这种技术有效吗?
    猜你喜欢
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    • 2018-03-11
    • 2017-06-12
    相关资源
    最近更新 更多