1. 对当前Run Loop中Selector Sources的取消

NSObject中的performSelector:withObject:afterDelay:方法将会在当前线程的Run Loop中根据afterDelay参数创建一个Timer,如果没有调用有inModes参数的方法,该Timer会运行在当前Run Loop的默认模式中,也就是NSDefaultRunLoopMode定义的模式中。

performSelector:withObject:afterDelay:方法的使用看起来还是很简单的。这里讲另外一个辅助函数,NSObject中静态的cancelPreviousPerformRequestsWithTarget方法。该方法就是专门用来取消取消performSelector:withObject:afterDelay:方法所创建的Selector source(内部上就是一个Run Loop的Timer source)。因此该方法和performSelector:withObject:afterDelay:方法一样,只限于当前Run Loop中。

我们可以利用cancelPreviousPerformRequestsWithTarget直接取消一个对象在当前Run Loop中的所有未执行的performSelector:withObject:afterDelay:方法所产生的Selector Sources,如下代码:

- (void)viewDidLoad
{
[super viewDidLoad]; [self performSelector:@selector(test:) withObject:nil afterDelay:1];
[self performSelector:@selector(test:) withObject:@"mgen" afterDelay:2];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
} - (void)test:(id)obj
{
NSLog(@"调用成功: %@", obj);
}

不会有任何输出,因为两个调用都被取消了。

如果想取消单独一个的话,需使用cancelPreviousPerformRequestsWithTarget:selector:object:方法,注意selectorobject参数需要一一对应。如下代码:

- (void)viewDidLoad
{
[super viewDidLoad]; [self performSelector:@selector(test:) withObject:[NSNumber numberWithInt:26] afterDelay:1];
[self performSelector:@selector(test:) withObject:[NSNumber numberWithInt:17] afterDelay:2];
[self performSelector:@selector(test:) withObject:[NSNumber numberWithInt:17] afterDelay:3];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(test:) object:[NSNumber numberWithInt:17]];
} - (void)test:(id)obj
{
NSLog(@"调用成功: %@", obj);
}

只会输出:

调用成功: 26

其他两个Selector都被取消了。

返回目录

2. 在NSThread中执行Selector

这个话题很简单,直接通过NSObjectperformSelectorInBackground:withObject:方法就可以,如下代码:

- (void)viewDidLoad
{
[super viewDidLoad]; [self threadInfo:@"UI"];
[self performSelectorInBackground:@selector(test:) withObject:nil]; } - (void)test:(id)obj
{
@autoreleasepool
{
[self threadInfo:@"test"];
}
}
- (void)threadInfo:(NSString*)category
{
NSLog(@"%@ - %@", category, [NSThread currentThread]);
}

输出:

UI - <NSThread: 0x71639e0>{name = (null), num = 1}
test - <NSThread: 0x7176ad0>{name = (null), num = 3}

这个方法完全等效于NSThreaddetachNewThreadSelector:toTarget:withObject:静态方法,那么上面NSObjectperformSelectorInBackground:withObject:方法调用完全可以替换成:

[NSThread detachNewThreadSelector:@selector(test:) toTarget:self withObject:nil];

当然,用户也可以自行手动创建一个NSThread来完成上述功能,代码如下:

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test:) object:nil];
[thread start];

这两种方法运行后的输出是和第一种类似的。

返回目录

3. 在NSThread中的Run Loop中执行Selector

这里需要的方法是NSObjectperformSelector:onThread:withObject:waitUntilDone:方法。由于是在另一个NSThread中执行Selector,所以我们需要手动开始Run Loop。首先需要在ViewController中定义两个字段,分别是NSThread和控制线程内Run Loop执行的flag。

@interface ViewController ()
{
NSThread *_thread;
BOOL _isNewThreadAborted;
}

接下来做的是执行这个线程,并且在线程中手动调用NSRunLooprunMode:beforeDate:方法。这里注意,如果Run Loop没有任何Source的话,该方法会立即返回,所以需要创建一个循环来持续调用Run Loop的runMode:beforeDate:方法。并在Selector执行结束后同时尝试结束这个循环。最终代码如下:

- (void)viewDidLoad
{
[super viewDidLoad]; [self threadInfo:@"UI"]; _isNewThreadAborted = NO;
_thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread:) object:nil];
//开始线程
[_thread start];
//在另一个线程中的Run Loop中执行Selector
[self performSelector:@selector(test:) onThread:_thread withObject:nil waitUntilDone:NO];
} //在新线程中创建并开始一个NSRunLoop
- (void)newThread:(id)obj
{
@autoreleasepool
{
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
while (!_isNewThreadAborted)
{
[currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"线程停止");
}
} //Selector执行
- (void)test:(id)obj
{
[self threadInfo:@"test"];
_isNewThreadAborted = YES;
} - (void)threadInfo:(NSString*)category
{
NSLog(@"%@ - %@", category, [NSThread currentThread]);
}

输出:

UI - <NSThread: 0x717e7e0>{name = (null), num = 1}
test - <NSThread: 0x8078a80>{name = (null), num = 3}
线程停止

最后注意performSelector:onThread:withObject:waitUntilDone:方法中最后的waitUntilDone参数,如果传YES的话,当前线程会等待Selector在另一个线程中执行完毕后继续执行。

4. UIPinchGestureRecognizer 与 NSObject Selector 的关联

if (recognizer.state == UIGestureRecognizerStateChanged) {

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(XXXSetNeedsDisplay) object:recognizer];

    // 相关的方法...

} else if (recognizer.state == UIGestureRecognizerStateEnded) {

[self performSelector:@selector(XXXSetNeedsDisplay) withObject:recognizer afterDelay:1.0f];

}

NSObject 中执行Selector 的相关方法的更多相关文章

  1. iOS: NSObject中执行Selector的相关方法

    本文转载至 http://www.mgenware.com/blog/?p=463 1. 对当前Run Loop中Selector Sources的取消 NSObject中的performSelect ...

  2. Java中子类和父类相关方法的执行顺序

    无意中看到下面一个题目,大家一起来看看最后的输出结果是什么.反正我看完之后,用IDE测试后感觉知识点得到巩固了. /** * 函数执行顺序测试 * Created by 萌小Q on 2017/5/1 ...

  3. NIO[读]、[写]在同一线程(单线程)中执行,让CPU使用率最大化,提高处理效率

    前几天写过一篇文章,讨论重写服务后,用ab进行压力测试,发现使用NIO后没提高什么性能,只是CPU使用率提高了,内存占用降低了. 之前的NIO实现模式,主要参考(基于事件的NIO多线程服务器)http ...

  4. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  5. Object-C 中的Selector 概念

    selector可以叫做选择器,其实指的就是对象的方法,也可以理解为C语言里面的函数指针,在面向对象里面的对应概念. @selector(xxxx)的作用是找到名字为xxxx的方法.一般用于[a pe ...

  6. Java I/O(4):AIO和NIO中的Selector

    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 在Java NIO的三大核心中,除了Channel和Buffer,剩下的就是Selector了.有的地方叫它选择器,也有叫多路复用器的(比如Ne ...

  7. 【Win 10 应用开发】在App所在的进程中执行后台任务

    在以往版本中,后台任务都是以独立的专用进程来运行,因此,定义后台任务代码的类型都要位于 Windows 运行时组件项目中. 不过,在14393中,SDK 作了相应的扩展,不仅支持以前的独立进程中运行后 ...

  8. [C#] 走进异步编程的世界 - 在 GUI 中执行异步操作

    走进异步编程的世界 - 在 GUI 中执行异步操作 [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5877042.html 序 这是继<开始接 ...

  9. 【python之路2】CMD中执行python程序中文显示乱码

    在IDLE中执行下面代码,中文显示正常: # -*- coding:utf-8 -*- st=raw_input("请输入内容")print st 但在CMD中执行e:\hello ...

随机推荐

  1. 转载《spring定时任务轮询(spring Task)》

    亲测可用 原文网址:http://blog.csdn.net/wanglha/article/details/51026697 本博主注:xmlns:task="http://www.spr ...

  2. C#开发微信公众化平台

     C#开发微信公众化平台 写在前面 服务号和订阅号 URL配置 创建菜单 查询.删除菜单 接受消息 发送消息(图文.菜单事件响应) 示例Demo下载 后记 最近公司在做微信开发,其实就是接口开发,网上 ...

  3. ASP.NET文件上传大小限制

    上传限制 我们以为的文件大小限制 我们大家都知道ASP.NET为我们提供了文件上传服务器控件FileUpload,默认情况下可上传的最大文件为4M,如果要改变可上传文件大小限制,那么我们可以在web. ...

  4. RemoteExt 远程验证

    public class RemoteExtAttribute : RemoteAttribute { private string _resourceKey; public RemoteExtAtt ...

  5. golang之math/rand随机数

    简单的随机数生成,结合时间模块初始化种子 package main import ( "fmt" "math/rand" "time" ) ...

  6. Oracle学习笔记(十二)

    十三.存储过程和存储函数1.掌握存储过程(相当于建立一个函数或者方法体,然后通过外部对其调用) 指存储在数据库中供所有程序调用的子程序叫做存储过程或存储函数. 相同点: 完成特定功能的程序 区别: 是 ...

  7. spark standalone集群部署 实践记录

    本文记录了一次搭建spark-standalone模式集群的过程,我准备了3个虚拟机服务器,三个centos系统的虚拟机. 环境准备: -每台上安装java1.8 -以及scala2.11.x (x代 ...

  8. 23 DesignPatterns学习笔记:C++语言实现 --- 2.6 Facade

    23 DesignPatterns学习笔记:C++语言实现 --- 2.6 Facade 2016-07-22 (www.cnblogs.com/icmzn) 模式理解

  9. ETL工作流缓慢原因查找方法

    What steps do you take to determine the bottleneck of a slow running ETL process? 如果ETL进程运行较慢,需要分哪几步 ...

  10. [label][Chrome-Extension] How to start Chrome Extension's development

    Firstly , you should read these two pages.  https://developer.chrome.com/extensions/overview https:/ ...