关于 performSelector 的一些小探讨

栏目: IOS · 发布时间: 6年前

内容简介:更多关于
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                   withObject:nil];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
    
}
  • 输出结果: 1,2,3,4
  • 原因: 因为 performSelector:withObject: 会在当前线程立即执行指定的 selector 方法。

例子②:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                   withObject:nil
                   afterDelay:0];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,4
  • 原因: 因为 performSelector:withObject:afterDelay: 实际是往 RunLoop 里面注册一个定时器,而在子线程中,RunLoop 是没有开启(默认)的,所有不会输出 3 。官网 API 作如下解释:
    关于 performSelector 的一些小探讨

例子③:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                   withObject:nil
                   afterDelay:0];
        [[NSRunLoop currentRunLoop] run];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,3,4
  • 原因: 由于 [[NSRunLoop currentRunLoop] run]; 会创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行 test 方法;并且 test 执行完后,RunLoop 中注册的定时器已经无效,所以还可以输出 4 (对比 例子⑥例子 )。

例子④:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                     onThread:[NSThread currentThread]
                   withObject:nil
                waitUntilDone:YES];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,3,4
  • 原因:因为 performSelector:onThread:withObject:waitUntilDone: 会在指定的线程执行,而执行的策略根据参数 wait 处理,这里传 YES 表明将会立即阻断 指定的线程 并执行指定的 selector 。官网 API 解释如下:

    关于 performSelector 的一些小探讨

例子⑤:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                     onThread:[NSThread currentThread]
                   withObject:nil
                waitUntilDone:NO];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,4
  • 原因:因为 performSelector:onThread:withObject:waitUntilDone: 会在指定的线程执行,而执行的策略根据参数 wait 处理,这里传 NO 表明不会立即阻断 指定的线程 而是将 selector 添加到指定线程的 RunLoop 中等待时机执行。(该例子中,子线程 RunLoop 没有启动,所有没有输出 3 )官网 API 解释如下:

    关于 performSelector 的一些小探讨

例子⑥:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                     onThread:[NSThread currentThread]
                   withObject:nil
                waitUntilDone:NO];
        [[NSRunLoop currentRunLoop] run];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,3
  • 原因: 由于 [[NSRunLoop currentRunLoop] run]; 已经创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行 test 方法;但是 test 方法执行完后,RunLoop 并没有结束(使用这种启动方式,RunLoop 会一直运行下去,在此期间会处理来自输入源的数据,并且会在 NSDefaultRunLoopMode 模式下重复调用 runMode:beforeDate: 方法)所以无法继续输出 4

例子⑦

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                     onThread:[NSThread currentThread]
                   withObject:nil
                waitUntilDone:NO];
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,3
  • 原因: 由于 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]]; 已经创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行 test 方法;但是 test 方法执行完后,RunLoop 并没有结束(使用这种启动方式,可以设置超时时间,在超时时间到达之前,runloop会一直运行,在此期间runloop会处理来自输入源的数据,并且会在 NSDefaultRunLoopMode 模式下重复调用 runMode:beforeDate: 方法)所以无法继续输出 4

例子⑧:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"1 - %@", [NSThread currentThread]);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2 - %@", [NSThread currentThread]);
        [self performSelector:@selector(test)
                     onThread:[NSThread currentThread]
                   withObject:nil
                waitUntilDone:NO];
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate distantFuture]];
        NSLog(@"4 - %@", [NSThread currentThread]);
    });
}
	
- (void)test
{
    NSLog(@"3 - %@", [NSThread currentThread]);
}
  • 输出结果: 1,2,3,4
  • 原因: 由于 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 已经创建的当前子线程对应的 RunLoop 对象并启动了,因此可以执行 test 方法;而且 test 方法执行完后,RunLoop 立刻结束(使用这种启动方式 ,RunLoop 会运行一次,超时时间到达或者第一个 input source 被处理,则 RunLoop 就会退出)所以可以继续输出 4

小结:

  1. 常用 performSelector 方法

    • 常用的 perform ,是 NSObject.h 头文件下的方法:

      - (id)performSelector:(SEL)aSelector;
      - (id)performSelector:(SEL)aSelector withObject:(id)object;
      - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
    • 可以 delay perform ,是 NSRunLoop.h 头文件下的方法:

      - (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;
    • 可以 指定线程 perform ,是 NSThread 头文件下的方法:

      - (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;
      - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
      - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg;
  2. RunLoop 退出方式:

    • 使用 - (void)run; 启动,RunLoop 会一直运行下去,在此期间会处理来自输入源的数据,并且会在 NSDefaultRunLoopMode 模式下重复调用 runMode:beforeDate: 方法;
    • 使用 - (void)runUntilDate:(NSDate *)limitDate; 启动,可以设置超时时间,在超时时间到达之前,RunLoop 会一直运行,在此期间 RunLoop 会处理来自输入源的数据,并且也会在 NSDefaultRunLoopMode 模式下重复调用 runMode:beforeDate: 方法;
    • 使用 - (void)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate; 启动,RunLoop 会运行一次,超时时间到达或者第一个 input source 被处理,则 RunLoop 就会退出。

更多关于 NSRunLoop的退出方式 可以看这篇 博文


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Coding the Matrix

Coding the Matrix

Philip N. Klein / Newtonian Press / 2013-7-26 / $35.00

An engaging introduction to vectors and matrices and the algorithms that operate on them, intended for the student who knows how to program. Mathematical concepts and computational problems are motiva......一起来看看 《Coding the Matrix》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具