多任务(1)

来源:互联网 发布:linux设置硬件时间 编辑:程序博客网 时间:2024/06/16 09:24

介绍:

多任务允许“后台执行”(background execution),意味着程序可以像往常一样工作---运行任务,产生大量的新线程,等候通知并对事件作出反应---但不会在屏幕上显示任何东西或者以任何方式和用户交互。当用户按下设备上的 Home 按钮,这在之前的版本将终止 iPhone 或者 iPad 上的应用程序,现在程序会被送到后台。 

当我们的程序转到后台(比如用户按下了 Home 按钮)然后回到前台(当用户再次选择 程序时),系统会发送一些不同的消息,期待被我们指派的应用程序委托对象接收。比如, 当我们的程序被送到后台,应用程序委托将会收到 applicationDidEnterBackground: 方法,当 程序被用户切到前台,应用程序委托将收到 applicationWillEnterForeground:委托消息。

  除了这些委托消息,在程序前后台切换时,iOS 也向运行中的程序发送通知。程序转入后台时发送的通知是 UIApplicationDidEnterBackgroundNotification,从后台切回前台发送的通知为 UIApplicationWillEnterForegroundNotification。你可以使用默认通知中心来注册这些通知。 


1.检测多任务Identifier可用性

 

1.1. 问题

你想知道正运行你程序的 iOS 设备是否支持多任务。 

1.2. 方案

调用 UIDevice 对象的实例方法 isMultitaskingSupported,如下: 

//检测是否支持多任务

- (BOOL)isMultitaskingSupported{

    BOOL result = NO;

    if ([[UIDevicecurrentDevice]respondsToSelector:@selector(isMultitaskingSupported)]) {

        result = [[UIDevicecurrentDevice]isMultitaskingSupported];

    }

    return result;

}



2.在后台完成一个长期任务(Long-Runing Task)


2.1. 问题
你希望能在程序被送入后台时,向 iOS 借点时间,来完成一个长期任务。 


2.2. 方案

使用 UIApplication 的 beginBackgroundTaskWithExpirationHandler: 实例方法。在你完成任务后,调用 UIApplication 的 endBackgroundTask:方法。 


2.3. 讨论

当一个 iOS 应用被送到后台,它的主线程会被暂停。你用 NSThread 的 detachNewThreadSelector:toTarget:withObject:类方法创建的线程也被挂起了。如果你想在后 台完成一个长期任务,就必须调用 UIApplication 的 beginBackgroundTaskWithExpirationHandler:实例方法,来向 iOS 借点时间.UIApplication的backgroundTimeRemaining 属性包含了程序完成他的任务可以使用的秒数。如果在这个期限内,长期任务没有被完成,iOS 将终止程序。每个对beginBackgroundTaskWithExpirationHandler:方法的调用,必须要相应的调用 endBackgroundTask:方法(UIApplication 的另一个实例方法)。也就是说,如果你向 iOS 要 更多时间来完成一个任务,你必须告诉 iOS 你什么时候能完成那个任务,那时,你的程序将 和其所有被暂停的线程被放入后台。

当你的程序在前台时,UIApplication 的 backgroundTimeRemaining 属性等于 DBL_MAX 常量,这是 double 类型可表示的最大值(和这个值相当的 integer 通常等于-1)。在 iOS 被 要求在程序被完全挂起之前给于更多的执行时间,这个属性指明了在完成任务前程序拥有多少秒。

在程序中你可以多次调用 beginBackgroundTaskWithExpirationHandler:方法。要记住的重 点是,当 iOS 为你的程序返回一个 token 或者任务标识(task identifier)时,你都必须调用 endBackgroundTask:方法,在运行的任务结束时,用来标志任务结束。如果你不这么做的话,iOS 会终止你的程序。

  在后台时,程序不应该执行完全的功能,也不应该处理大量数据。事实上,他们只应该完成一个长期任务。

比如,一个程序正在调用一个 web service API,并且还没有从服务器上的那个 API 接收 到响应。在此期间,如果程序被送入后台,它可以请求更多的时间,直到它从服务器收到响 应。一旦响应被接收,程序必须保存其状态,并调用 UIApplication 的 endBackgroundTask:实例方法将任务标记为完成。 


让我们看一个例子。我将从在应用程序委托中定义一个 UIBackgroundTaskIdentifier 类型 的属性开始。同时,让我们定义一个 NSTimer,当程序被送到后台时,我们将用它每隔 1 秒 向控制台窗口输出一条消息: 

.h

#import <UIKit/UIKit.h>


@interface AppDelegate :UIResponder <UIApplicationDelegate>


@property (strong,nonatomic) UIWindow *window;

@property (nonatomic ,unsafe_unretained)UIBackgroundTaskIdentifier backgroundTaskIdentifier;

@property (nonatomic ,strong)NSTimer *myTimer;


@end


.m


//.1现在,让我们创建定时器,并在程序被送到后台时启动它:


- (void)timerMethod:(NSTimer *)paramSender{

    NSTimeInterval backgroundTimeRemaining = [[UIApplicationsharedApplication]backgroundTimeRemaining];//remaining adj.剩余的,剩下的

    if (backgroundTimeRemaining == DBL_MAX) {

        NSLog(@"Background Time Remaining = Undetermined");

    }else{

        NSLog(@"Background Time Remaining = %.02f Seconds", backgroundTimeRemaining);

    }

}

- (void)applicationDidEnterBackground:(UIApplication *)application {

    self.myTimer = [NSTimerscheduledTimerWithTimeInterval:1.0ftarget:selfselector:@selector(timerMethod:)userInfo:nilrepeats:YES];

    self.backgroundTaskIdentifier = [applicationbeginBackgroundTaskWithExpirationHandler:^{

        [selfendBackgroundTask];

    }];

    //  expiration /ˌekspɪ'reɪʃ(ə)n/ 截止,告终;呼气,吐气

}



//.2 你可以看到,在后台任务的完成处理者(completion handler),我们调用了应用程序委托的 endBackgroundTask 方法。这是一个我们编写的方法,如下:

- (void)endBackgroundTask{

    dispatch_queue_t mainQueue =dispatch_get_main_queue();

    __weak AppDelegate *weakSelf =self;

    dispatch_async(mainQueue, ^{

        AppDelegate *strongSelf = weakSelf;

        if (strongSelf != nil) {

/*在长期任务结束后,我们需要做一些事情进行清理:

    1. 结束所有的线程和定时器,不管他们是基础定时器还是 GCD中创建的。

    2.调用 UIApplication endBackgroundTask:方法来结束后台任务。

    3.将任务标识设置为 UIBackgroundTaskInvalid,标志我们的任务结束。

*/

            [strongSelf.myTimer invalidate];

            [[UIApplicationsharedApplication]endBackgroundTask:self.backgroundTaskIdentifier];

            strongSelf.backgroundTaskIdentifier =UIBackgroundTaskInvalid;

        }

        NSLog(@"结束后台");

    });

}

//.3 最后,当我们的应用回到前台,如果我们的后台任务还在执行中,我们需要确保我们在干掉它:

- (void)applicationWillEnterForeground:(UIApplication *)application {

    if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid) {

        [self endBackgroundTask];

    }

}

模拟运行时,进入后台一直等待时打印结果:

2014-12-19 11:24:14.283多任务Identifier[2079:332066] Background Time Remaining = 179.01 Seconds

2014-12-19 11:24:15.283多任务Identifier[2079:332066] Background Time Remaining = 178.01 Seconds

2014-12-19 11:24:16.282多任务Identifier[2079:332066] Background Time Remaining = 177.01 Seconds

......

2014-12-19 11:27:07.273多任务Identifier[2079:332066] Background Time Remaining = 6.01 Seconds

2014-12-19 11:27:08.274多任务Identifier[2079:332066] Background Time Remaining = 5.01 Seconds

2014-12-19 11:27:08.288多任务Identifier[2079:332066]结束后台



进入后台,马上将应用进入前台,打印结果:

2014-12-19 11:33:39.240多任务Identifier[2194:352062] Background Time Remaining = 179.01 Seconds

2014-12-19 11:33:40.240多任务Identifier[2194:352062] Background Time Remaining = 178.01 Seconds

2014-12-19 11:33:41.240多任务Identifier[2194:352062] Background Time Remaining = 177.01 Seconds

2014-12-19 11:33:42.240多任务Identifier[2194:352062] Background Time Remaining = 176.01 Seconds

2014-12-19 11:33:42.354多任务Identifier[2194:352062]结束后台


2.4 总结

在我们的例子中,不论何时程序被送到后台,我们都会要求更多时间以完成一个长期任务(例如,在这里是我们计时器的代码)。在我们的时间里,我们不断的读取 UIApplication 实例中 backgroundTimeRemaining 属性的值,将它打印到控制台。在 UIApplication 的 beginBackgroundTask WithExpirationHandler: 实例方法中,在程序的额外时间内完成一个长期任务之前,我们提供的代码将被执行(一版大概在任务过期前 5 到 10 秒)。在此,我们只要调用 UIApplication 的 endBackgroundTask:实例方法来结束任务。 

 当一个程序被送到后台而且它从 iOS 请求了额外执行时间,在执行时间 完成之前,程序可以被用户唤醒并被带回到前台。如果你在程序被送到后台时请求过执行一 个长期任务,那么此时你必须使用 UIApplication 的 BackgroundTask:实例方法结束这个长期任务。 

 

 







0 0
原创粉丝点击