iOS延时执行 - performSelector

延时执行 - performSelector

performSelector在运行时去动态找方法,在编译时不做校验,所以编译期间不存在这个方法,是不会报错的。但是运行时不存在就会崩溃。为了程序的健壮性,在执行这个方法之前最好做一下判断:

// 判断是否有指定方法
+ (BOOL)respondsToSelector:(SEL)aSelector;

由于这个动态查找方法,可能存在方法不存在的问题,编译器会报警告⚠️, 可以采用下面的方法,让编译器忽略警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
          [observer performSelector:info->_action withObject:change withObject:object];
#pragma clang diagnostic pop

1. 同步立刻执行

定义在<NSObject.h>文件中的三个方法,表示当前线程(不分主线程子线程)同步立刻执行方法。

最多只能传2个参数,如果有更多的参数,可以用字典、数组、NSInvocation 包装一下。

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

2. 异步延迟执行

定义在<NSRunloop.h>文件中的 NSObject 的2个分类方法,表示当前线程(不分主线程子线程)异步延迟执行方法。

  • 底层会创建一个 Timer,添加到当前线程的运行循环上去执行,可以指定加到什么mode上。
  • 对于主线程来讲,运行循环自动开启,会执行成功。
  • 对于子线程来讲,如果运行循环没开启,则不能执行成功。需要先调用完延迟执行方法后再调用开启运行循环[[NSRunLoop currentRunLoop]run]; 因为源码逻辑中,开启某线程的Runloop,必须具有timer、source、observer任一事件才能触发开启。
  • 注意:调用该方法所在的 VC 释放时主动调用取消函数,以确保不会内存泄露。
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

// 取消执行
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(nullable id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;

2.1 应用:防止暴力点击

1. 一段时间内多次点击只响应最后一次

狂点按钮,就会产生多次响应。如果想做到 2 秒内不论点击多少次,都只响应最后一次的话,可以使用延迟执行:

在点击方法内部先取消之前的延迟执行,再触发新一轮的延迟执行。这样在延迟时间 2 秒内的多次点击事件,都可以被取消掉,只响应最后一次。

- (IBAction)buttonClick:(id)sender {
    id params;
    [[self class]cancelPreviousPerformRequestsWithTarget:self
                                                selector:@selector(realResponse:)
                                                  object:params];
    [self performSelector:@selector(realResponse:)
               withObject:params
               afterDelay:2];
}
 
- (void)realResponse:(id)objcet {
    NSLog(@"realResponse");
}

2.点击后,按钮置灰,一段时候后再恢复

-(void)buttonClicked:(id)sender{
  self.button.enabled =NO;
  [selfperformSelector:@selector(changeButtonStatus)withObject:nilafterDelay:1.0f];
}

-(void)changeButtonStatus{
    self.button.enabled =YES;
}

3. 切换线程执行

waitUntilDone参数:

  • YES 表示阻塞当前线程,等待这个方法执行完,再向下执行;
  • NO 表示不等待方法执行完,直接向下执行。
  • 线程执行完任务会立刻销毁

// 去主线程执行方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

// 去指定线程执行方法
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

// 开启一个子线程去后台执行方法
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值