2010-06-03 56 views
2

我想在主线程上执行动画(原因是UIKit对象不是线程安全的),但在一些单独的线程中做好准备。我有(baAnimation - 是CABasicAnimation分配&前inited):使用NSInvocation在主线程上执行选择器

SEL animationSelector = @selector(addAnimation:forKey:); 
NSString *keyString = @"someViewAnimation"; 

NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[workView.layer methodSignatureForSelector:animationSelector]]; 
[inv setTarget:workView.layer]; 
[inv setSelector:animationSelector]; 
[inv setArgument:baAnimation atIndex:2]; 
[inv setArgument:keyString atIndex:3]; 
[inv performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:NO]; 

我得到:

*** + NSCFString长]:无法识别的选择发送到类0x1fb36a0

电话:

>  #0 0x020984e6 in objc_exception_throw 
>  #1 0x01f7e8fb in +[NSObject doesNotRecognizeSelector:] 
>  #2 0x01f15676 in ___forwarding___ 
>  #3 0x01ef16c2 in __forwarding_prep_0___ 
>  #4 0x01bb3c21 in -[CALayer addAnimation:forKey:] 
>  #5 0x01ef172d in __invoking___ 
>  #6 0x01ef1618 in -[NSInvocation invoke] 

[workView.layer addAnimation:baAnimation forKey:@"someViewAnimation"];工作正常。我究竟做错了什么?

回答

6

除了[inv retainArguments](如Chris Suter所述)之外,还需要将参数作为指针传递给基础内存。援引API:

“当参数值是一个对象,将指针传递到可变(或存储器),从该对象应该被复制:

NSArray *anArray; 
[invocation setArgument:&anArray atIndex:3]; 

+3

这应该是公认的正确答案,因为这是更大的问题(根本不传递正确的东西,而不是内存管理问题) – user102008 2011-08-01 01:22:13

2

你要么需要添加[inv retainArguments]或更改waitUntilDone参数设置为YES,你这样做之前,我只想说,你做了什么是相当不可读。

我会做的是存储任何状态,你的实例变量需要,然后当你准备好了,只是做:

[self performSelectorOnMainThread:@selector (startAnimation) withObject:nil waitUntilDone:NO];

而且上分配和线程初始化一个CABasicAnimation是不必要的(它在主线程上不需要任何明显的时间),并且仍然具有潜在的危险性。将处理器密集型工作留在单独的线程上,但不要其他任何东西。

+0

非常感谢。真的,我非常同意你的看法,这个任务有“理论上的”目标(只是为了尝试这种方式)。 – kpower 2010-06-03 07:47:38

+0

@Chris Suter - 答案很好,但其余的建议都违背了关于线程的公认智慧。在线程之间定义良好的入口和出口处传递参数比尝试同步共享资源访问要容易得多。这不仅仅是我说话。以下是苹果对此主题的建议http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW6 – DougW 2011-10-28 18:17:23

+0

@ DougW我认为这取决于情况。一般来说,你是对的,但最重要的目标应该是最大限度地提高可读性,而且我认为许多程序员犯的一个常见错误是盲目地遵循模式或规则。在这种情况下,如果不知道更多关于这个问题的信息,很难说清楚,我怀疑使用实例变量来记录状态会比做你的建议更简单和更易维护。 – 2011-11-08 01:59:00

4

如果有你的NSInvocation中有一个或多个参数,然后我会建议创建一个新的类别来调用主线程上的选择器。这是我如何解决了这个:


NSInvocation的+ MainThread.h

#import <Foundation/Foundation.h> 

@interface NSInvocation (MainThread) 
- (void)invokeOnMainThreadWithTarget:(id)target; 
@end 

NSInvocation的+ MainThread.m

#import "NSInvocation+MainThread.h" 

@implementation NSInvocation (MainThread) 

- (void)invokeOnMainThreadWithTarget:(id)target { 
    [self performSelectorOnMainThread:@selector(invokeWithTarget:) withObject:target waitUntilDone:YES]; 
} 

@end 
+0

好主意,谢谢 – 2012-12-08 03:26:27

相关问题