iOS编程基础-OC(十一)-Foundation框架中的系统服务:并发机制和线程

来源:互联网 发布:传奇天下轮回每层数据 编辑:程序博客网 时间:2024/06/02 06:30

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动! 

     

     第11章 Foundation框架中的系统服务

     


   11.5 并发机制和线程

      

     使用支持并发机制和线程的类可以实现管理线程的功能,以及通过线程并行执行多个代码块的功能;

      

     接下来介绍这些类,第17章还会详细介绍OC平台的并行编程方法;

      

     11.5.1 线程管理

      

     NSTask类和NSThread类:

        用于管理线程和进程;

      

     使用NSTask类可以在OC运行时系统中创建和管理进程;

        NSTask实例作为独立进程进行操作,它不与其他进程共享内存;包括创建它的进程;

        一个NSTask对象只能运行一次,而且其环境需要在它运行之前配置好;

        比如:

            我们使用下述方法,创建和启动一个任务,执行当前目录中名为greeting的程序;

            NSTask * task = [NSTask launchTaskWithLaunchPath:@"./greeting" argments:nil];//OS X

        也可以:

            NSTask * hello = [[NSTask alloc] init];

            [hello setLaunchPath:@"./greeting"];

            [hello launch];

        可以使用isRunning方法查询任务状态;

      

      

     线程是一种操作系统机制,用于以并行的方式执行多个指令序列;

        线程通常被实现为轻量级进程,因为同一个进程中可以同时存在多个线程;

        同一个进程中的线程可以共享计算机中的内存和其他资源;

      

     使用NSThread类可以创建和控制线程;

        这个类中有很多方法,这些方法可以用来创建和初始化NSThread对象、启动和停止线程、配置线程以及查询线程及其执行环境;

        使用NSThread的detachThreadSelector:toTarget:withObject:方法,可以创建和启动新线程;

        使用setThreadPriority可以设置线程的优先权;(1.0为最高等级优先权)

        使用cancel方法可以向线程发送取消信号;

-(void)testCurrentTargetSEL{    NSLog(@"Thead operation doing");}
  

 [NSThread detachNewThreadSelector:@selector(testCurrentTargetSEL) toTarget:self withObject:nil];//创建并执行(无法获取)        NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(testCurrentTargetSEL) object:nil];//创建获取 手动启动    [thread setThreadPriority:1.0];    [thread start];    [thread cancel];


      log:

      2017-12-25 16:24:59.920413+0800 精通Objective-C[23587:8140370] Thead operation doing


     11.5.2 并行操作

      

     NSOperation、NSBlockOperation和NSInvocationOperation类:

        用于管理一个或多个操作、代码以及单独任务关联数据的并行执行过程;

     

     操作队列:

        是指提供并行执行任务功能的OC对象;

        每个任务(即操作)都定义了需要执行的程序和与之相关的数据;而且会被封装在块对象或NSOperation类的具体子类中;

      

     NSOperation是一个抽象类,用于封装单个任务的代码和相关数据;

        在处理非并行任务时,具体子类通常只需要重写主要方法;

        在处理并行任务时,至少必须重写start、isConcurrent、isExecuting和isFinished方法;

      

     使用NSOperationQueue类可以通过队列系统控制NSOperation对象的执行;

        操作队列会使用线程执行操作;(这类实现细节是隐式的)

        如[NSOperationQueue mainQueue];

        可以通过addOperation:来添加操作;

      

     11.5.3 锁定

      

     使用NSLock、NSDistributedLock、NSConditionLock和NSRecursiveLock类可以为同步执行的代码创建锁;

        NSLock类为并行编程方式实现了一个基本的互斥锁;(互斥锁)

        该类遵守NSLocking协议,因此实现了用于获取和释放锁的lock方法和unlock方法;

      

     NSDistributedLock类:(分布锁)

        定义了可由多台主机上的多个应用程序使用的锁,该锁可以控制对共享资源的访问;

      

     NSConditionLock类:(条件锁)

        定义了只能在特定条件下获取和释放的锁;

      

     NSRecursiveLock类:(递归所)

        定义了在不导致死锁的前提下,可由同一线程使用多次的锁;

        该锁会记录自身被使用的次数,在释放该锁前必须先调用对应的方法解锁对象,以实现所定和解锁操作的平衡;

      

     11.5.4 计时器和运行循环

      

     运行循环:

        是一种基于线程的机制;用于调度任务和协调收到的输入事件;

      

        如果程序的线程 需要回应 入站事件,就必须将之附到运行循环中,以在新事件出现时唤醒该线程;

      

     ios的UIApplication类的run方法,可以将应用程序的主循环添加到标准启动序列中,因此,使用xcode模板创建的程序,通常无需编写运行循环代码;

     其他情况下,如创建命令行程序,如果你编写的程序需要回应来自输入资源的事件,就需要编写运行循环代码;

      

     Foundation框架提供很多异步输入功能的类(如网络、数据流I/O),应该在程序中将这些类与运行循环结合起来使用;

      

     NSRunLoop类:

        提供了管理运行循环的API;

        这个类含有很多方法,使用它们可以访问运行循环和模式、管理计时器和端口、运行某个循环和管理消息;

        使用currentRunLoop方法可以获取当前的运行循环(代表当前线程的NSRunLoop对象);

            如果线程的运行循环还不存在,该方法可以创建运行循环,并返回它;

      

     运行模式:为运行循环定义了输入源;

        Foundation框架定义了一系列用于设置可用运行循环模式的常数;

        常数NSDefaultRunLoopMode是最常用的运行循环模式;

      

     多种NSRunLoop方法运行循环;

        使用run方法可以将线程添加到NSDefaultRunLoopMode实例的永久循环中,然后线程就可以在NSDefaultRunLoopMode实例的生命周期中处理所有来自输入源的事件;

        如果要使用能够停止的循环,就不应该使用该方法,可以使用根据收到的输入信息或指定的时间运行相应循环的方法;

            使用runModel:beforeData:方法可以在NSDefaultRunLoopMode实例中运行一次循环,在从输入源收到时间和beforeDate:参数设置的时间点之前,不接受输入信息;

      

        示例:线程会一直等待所需输入的信息;

 

    NSRunLoop * loop = [NSRunLoop currentRunLoop];    [loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];


     如果[NSDate distantFuture]中的日期参数值为无穷大,线程就会一直等待所需输入的信息;

     

     NSTimer类:

        用于在经过了指定的时间后,向目标对象发送消息;

        将它的实例与NSRunLoop实例一起使用,可以通过同步的方式向线程发送事件;

        使用NSTimer实例可以设置运行循环对象等到输入的最长时间;

     

     使用NSTimer类的方法可以创建和初始化计时器、启动计时器、停止计时器和获取计时器信息;

        使用[NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) invocation:(nonnull NSInvocation *) repeats:(BOOL)];方法可以创建经过指定时间后取消的计时器;

        该计时器可用于调用消息设置时间间隔,并且可以在有需要时重复计时;

        使用invalidate方法可以使计时器不再启动;

        isValid方法能够返回表明当前计时器是否合法的布尔值;

     

     说了这么多,接下来实践一下;

      

     11.5.5 创建Bonjour网络服务客户端

     

     接下来将编写一个使用Bonjour网络服务API和运行循环的程序;

        该程序会创建一个服务端浏览器,后者会以异步方式查找指定类型的已注册服务;

     

     我们新建一个命令行应用程序命名为C11BonjourClient;

        接下来在工程目录中创建一个使用加载URL的API下载URL资源的类:C11BonjourClient类;

        更新相关代码如下:

     (Code C11BonjourClient.h C11BonjourClient.m)

     注意以下代码是在单独的一个工程中的;

     

#import <Foundation/Foundation.h>@interface C11BonjourClient : NSObject<NSNetServiceBrowserDelegate>@property (retain) NSNetServiceBrowser * serviceBrowser;@property BOOL finishedLoading;@end

#import "C11BonjourClient.h"@implementation C11BonjourClient-(instancetype)init{    if (self = [super init]) {        _finishedLoading = NO;        _serviceBrowser = [[NSNetServiceBrowser alloc] init];//浏览器实例        [_serviceBrowser setDelegate:self];//浏览器实例的代理设置为当前对象    }    return self;}#pragma mark -#pragma mark NSNetServiceBrowserDelegate methods-(void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser{    NSLog(@"Begin searching");}-(void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing{    }-(void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing{    NSLog(@"Find server:%@",service);    if (!moreComing) {//条件判断:服务浏览器是否正在等待其他服务        //没有心的服务 停止搜索        [self.serviceBrowser stop];    }}-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser{    //停止搜索,将标记设置为退出循环运行    NSLog(@"Stop searching");    self.finishedLoading = YES;}@end

     分析:

        C11BonjourClient类的接口采用NSNetServiceBrowserDelegate协议,因此会通过异步的方式从NSNetServiceBrowser实例加载数据;

        属性serverBrowser属性就是NSNetServiceBrowserDelegate实例;

        finishedLoading属性用于指明NSNetServiceBrowser实例完成数据加载的时间;

     

        当服务浏览器实例开始搜索服务时,会调用相应的回调方法;

     

     编写好了C11BonjourClient类,接下来我们通过Bonjour协议使用该类搜索已注册的服务;

        更新该工程的main函数中代码如下:

     (Code main.m)

     

#import <Foundation/Foundation.h>#import "C11BonjourClient.h"int main(int argc, const char * argv[]) {    @autoreleasepool {        // insert code here...        NSLog(@"Hello, World!");                //获取当前的运行循环查看信息        NSRunLoop * loop = [NSRunLoop currentRunLoop];                //创建一个客户端,并将其服务浏览器实例添加到当前的运行循环中        C11BonjourClient * client = [[C11BonjourClient alloc] init];                //查找指定的服务类型        [client.serviceBrowser searchForServicesOfType:@"_ipp._tcp." inDomain:@"local."];                //一直循环,直到服务浏览器停止        while (!client.finishedLoading && [loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {                    }            }    return 0;}

     表达式[loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]会执行一次运行循环,阻止从输入源接收其他信息;

        接收信息后,该消息会在当前线程(即被调用的相应委托方法)中被处理,而且循环会再次开始运行;

        因此在设置finishedLoading之前,不会退出while循环;

     

     这个练习展示了如何编写一个使用Foundation框架API以异步的方式寻找已注册服务的程序;

     这个程序并不完整,已注册服务可以自行实现类进行测试,书中内容至此结束,待后续可查找资料补充实现,进行测试;


接下来研究处理url的方式。


阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 大连甘井子学区房 极度掌控by白栖井 井架 钻井井架 井栏壶 井栏 井栏紫砂壶价格 井栏紫砂壶 井格 井格老灶火锅 井格火锅 井格基础 韩居丽格 格桑加措 钢笔书法井圆格 井柏染 渫怎么读 井加点 井加一点 井点 一个井一个点 井一个点 井加一点读什么 井中间一个点 一个井中间一个点 井点什么字 轻型井点降水 井里面一个点 井点降水 井里面一个点念什么 井中间一点 喷射井点降水 井里面一点 井中间一点读什么 井字加一点 轻型井点降水施工方案计算 轻型井点降水适用范围 井子中间加一点念什么 井点降水施工图片 井点降水施工单位