我想在主线程上执行动画(导致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 length]:无法识别的选择器发送到类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"];
工作正常。我做错了什么?
答案 0 :(得分:6)
除了[inv retainArguments](如Chris Suter所述),您还需要将参数作为指针传递给底层内存。引用API:
“当参数值是一个对象时,传递指向应该从中复制对象的变量(或内存)的指针:
NSArray *anArray;
[invocation setArgument:&anArray atIndex:3];
“
答案 1 :(得分: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
答案 2 :(得分:2)
您需要添加[inv retainArguments]
或将waitUntilDone参数更改为YES,但才能执行此操作,我只想说您所做的事情非常难以理解。
我要做的是在实例变量中存储您需要的任何状态,然后当您准备好时,只需执行:
[self performSelectorOnMainThread:@selector (startAnimation) withObject:nil waitUntilDone:NO];
在线程上分配和初始化CABasicAnimation也是不必要的(在主线程上不需要花费任何明显的时间),并且仍然存在潜在危险。保持处理器密集型工作在一个单独的线程上,但不是其他任何东西。