将NSTimer添加至RunLoop中的两种方法区别

-
(
BOOL)application:(UIApplication
*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

    self.window
= [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    

    //用NSObject的方法创建一个多线程

    [self
performSelectorInBackground:@selector(multiThread) withObject:nil];

    

    self.window.backgroundColor
= [UIColor whiteColor];

    [self.window
makeKeyAndVisible];

    return

YES;

}

-
(
void)multiThread

{

    NSAutoreleasePool
*pool = [[NSAutoreleasePool alloc] init];

    if

(![NSThread isMainThread]) {

        

        //
第1种方式

        //此种方式创建的timer已经添加至runloop中

//       
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

        //保持线程为活动状态,才能保证定时器执行

//       
[[NSRunLoop currentRunLoop] run];//已经将nstimer添加到NSRunloop中了

        

        //第2种方式

        //此种方式创建的timer没有添加至runloop中

       NSTimer
*timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

        //将定时器添加到runloop中

        [[NSRunLoop
currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

        [[NSRunLoop
currentRunLoop] run];

        NSLog(@"多线程结束");

    }

     [pool
release];

}

-
(
void)timerAction

{

    //定时器也是在子线程中执行的

    if

(![NSThread isMainThread]) {

        NSLog(@"定时器");

    }

}

理解run loop后,才能彻底理解NSTimer的实现原理,也就是说NSTimer实际上依赖run loop实现的。

先看看NSTimer的两个常用方法:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget
selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
 //生成timer但不执行

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget
selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
 //生成timer并且纳入当前线程的run loop来执行

NSRunLoop与timer有关方法为:

- (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode; //在run
loop上注册timer

主线程已经有run loop,所以NSTimer一般在主线程上运行都不必再调用addTimer:。但在非主线程上运行必须配置run loop,该线程的main方法示例代码如下:

- (void)main

{

  NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timer:) userInfo:nil repeats:YES];

  NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

  [runLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; //实际上这步是不需要,scheduledTimerWithTimeInterval已经纳入当前线程运行。如果使用timerWithTimeInterval则需要

  while (condition)

    [runLoop run];

}

实际上这个线程无法退出,因为有timer事件需要处理,[runLoop run]会一直无法返回。解决办法就是设置一个截止时间:

[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; //每隔10秒检查下线程循环条件,当然时间值可以根据实际情况来定。

我们通常在主线程中使用NSTimer,有个实际遇到的问题需要注意。当滑动界面时,系统为了更好地处理UI事件和滚动显示,主线程runloop会暂时停止处理一些其它事件,这时主线程中运行的NSTimer就会被暂停。解决办法就是改变NSTimer运行的mode(mode可以看成事件类型),不使用缺省的NSDefaultRunLoopMode,而是改用NSRunLoopCommonModes,这样主线程就会继续处理NSTimer事件了。具体代码如下:

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timer:) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

大家可以参看博文http://bluevt.org/?p=209,加深理解NSTimer和NSRunLoop的关系。

以前博文中提到延迟调用的方法,其实就是在当前线程的run loop上注册timer来实现定时运行的。所以如果是在非主线程上使用,一定要有一个run loop。

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument
afterDelay:(NSTimeInterval)delay inModes:(NSArray*)modes;

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument
afterDelay:(NSTimeInterval)delay;

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-21 15:16:45

将NSTimer添加至RunLoop中的两种方法区别的相关文章

UIImage加载图片的两种方法区别

Apple官方的文档为生成一个UIImage对象提供了两种方法加载图片: 1. imageNamed,其参数为图片的名字: 2. imageWithContentsOfFile,其参数也是图片文件的路径. 那么两种有什么区别吗? 肯定是有的.根据Apple的官方文档: imageNamed: 这 个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话.如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这 个对象.因此imageNamed的优点是当加载时会缓存图

在SQL查询结果中添加自增列的两种方法

解决办法<一>:如果想查询出这个表的信息,并添加一列连续自增的ID,可用如下查询语句: SELECT Row_Number() over ( order by getdate() ) as init , * FROM 表名 解决办法<二>: 使用关键字IDENTITY创建临时表 SELECT IDENTITY(int,1,1) as Nid,* INTO #T FROM 表名 SELECT * FROM #T 原文地址:https://www.cnblogs.com/crrc/p/

mybais 的映射文件,需要从poviderDao.java 的一个 方法 public getProvidersFactors(参数 ) 中传入多个参数到providerDao.xml中的两种方法

方法一: 直接以对象的整体的形式去传入到xml文件中,当然这时候用过满足的条件是:你所想传入的所有的参数,应该都是包含在一个对象中的,此时可以以对象的形式去传入到xml中 如下图示例 实体类 private String id; private String companyName; private String managerName; private String phone; private String address; private String type; #ProviderDao

将整数n这个数字转换为对应的字符串,保存到s中(两种方法)

方法一. 用循环的方法取出每一位,存到字符数组中,最后将数组翻转. 代码实现如下: #include<stdio.h>#include<string.h>#include<assert.h>#define MAX 20void reverse(char *left, char *right){ assert(left); assert(right); while (left < right) {  int tmp = *left;  *left = *right;

Linux 添加开机启动项的两种方法

1.编辑文件 /etc/rc.local vim /etc/rc.local #!/bin/sh # # This script will be executed *after* all the other init scripts. # You can put your own initialization stuff in here if you don't # want to do the full Sys V style init stuff. touch /var/lock/subsy

C#把某个数组的一部分复制到另一个数组中的两种方法:Buffer.BlockCopy和Array.Copy

static void Main(string[] args) { int[] src = new[] { 1, 2, 3, 4, 5, 6 }; const int destLen = 4;//目标数组大小 int int_size = sizeof(int);//用于获取值类型的字节大小. int[] dest = new int[destLen]; //只支持基元类型,按字节偏移复制 Buffer.BlockCopy(src, (src.Length - destLen) * int_si

android中的两种上下文区别

1.this    继承于content      子类 2.getAppliCationContext()     返回值为context    父类 父类有的子类都有,子类父类不一定有. 在对话框只能用this,不能用geiAppliCationContext()

java String转Long两种方法区别

第一种:包装类型:Byte,Integer,Short,Long,Boolean,Character,Float,Double等8种 Long.valueOf("String")返回Long包装类型 第二种:基本数据类型:byte,int,short,long,boolean,char,float,double等8种 Long.parseLong("String")返回long基本数据类型 原文地址:https://www.cnblogs.com/zlw-xf/p/

Js类的静态方法与实例方法区分以及jQuery如何拓展两种方法

上学时C#老师讲到对象有两类方法,静态方法(Static)和实例方法(非Static),当时不理解静态是为何意,只是强记. 后来从事了前端的工作,一直在对类(即对象,Js中严格来说没有类的定义,虽众所周知,这里还是赘述一番,以免产生歧义)的操作上,严重缺乏整体概念,最近看extetnd中再次提到拓展静态方法与实例方法,故而再次百度,才幡然领悟,其实一直有用,只是不知其专业术语呀,哈哈~ 静态方法,属于类的方法,即类可以直接调用的方法.为类所有实例化对象所共用(但不能用实例对象之间调用),所以静态