2

我想在主线程上执行动画(因为 UIKit 对象不是线程安全的),但在一些单独的线程中准备它。我有(baAnimation - CABasicAnimation 之前已分配和初始化):

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"];工作正常。我究竟做错了什么?

4

3 回答 3

6

除了 [inv retainArguments](如 Chris Suter 所述)之外,您还需要将参数作为指向底层内存的指针传递。引用 API:

“当参数值是一个对象时,传递一个指向应该从中复制对象的变量(或内存)的指针:

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

"

于 2010-09-16T19:21:22.200 回答
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
于 2011-12-08T16:20:34.303 回答
2

您需要添加[inv retainArguments]或更改 waitUntilDone 参数为 YES,在您这样做之前,我只想说您所做的非常难以理解。

我要做的是将您需要的任何状态存储在实例变量中,然后当您准备好时,只需执行以下操作:

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

此外,在线程上分配和初始化 CABasicAnimation 是不必要的(在主线程上执行它不会花费任何明显的时间),并且仍然具有潜在的危险。将处理器密集型工作保持在单独的线程上,而不是其他任何东西。

于 2010-06-03T07:38:50.833 回答