第一步:配置NSInvocation
- (id)performSelector:(SEL)aSelector withArgument:(id)anArgument{
if (aSelector == nil) return nil;
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = aSelector;
//NSInvocation 有两个隐藏参数,所以anArgument
if ([anArgument isKindOfClass:[NSArray class]]) {
NSInteger count = MIN(signature.numberOfArguments-2, [(NSArray *)anArgument count]);
for (int i = 0; i< count; i++) {
const char *type = [signature getArgumentTypeAtIndex:i + 2];
//需要做参数类型判断然后解析成对应类型,这里默认所有参数都是OC对象
if (strcmp(type, "@") == 0) {
id argument = anArgument[i];
[invocation setArgument:&argument atIndex:2+i];
}
}
}
[invocation invoke];
return invocation;
}
第二步 :创建NSTimer需要调用的方法
- (void) run:(NSString *)run drink:(NSArray *)drink sleep:(NSDictionary *)sellp{
NSLog(@"run------%@",run);
NSLog(@"drink------%@",drink);
NSLog(@"sleep------%@",sellp);
}
第三步:使用NSTimer
[NSTimer scheduledTimerWithTimeInterval:1.0
invocation:[self performSelector:@selector(run:drink:sleep:) withArgument:@[@{@"key":@"sellp"},@"run",@[self.view,@"1"]]]
repeats:YES];
特别提醒 :
1、临时变量抽取
EXC_BAD_ACCESS.png这样写导致报错EXC_BAD_ACCESS。
原因:
[NSTimer scheduled....]
NSTimer 调用这个方法系统会自动将这个临时对象保持住,即retainCount 系统帮你加1;但是成员变量,invocation 是自己创建的临时对象,用一次就释放掉了,等下一次runloop进入的时候NSInvocation 对象被释放,所以奔溃。
所以还是用第三部中的方法就可以了
2、NSTimer保险使用
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
可能出现的问题:如果默认加载主线程的话,人为操作UI或者代码为主线程添加操作,导致主线程优先处理UI事件。NSTimer就被阻塞。
网友评论