多线程的理解

进程

维基百科:程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。若干进程有可能与同一个程序相关系,且每个进程皆可以同步(循序)或异步(平行)的方式独立运行。

  在iOS系统中,一个APP的运行实体代表一个进程。一个进程有独立的内存空间、系统资源、端口等。在进程中可以生成多个线程、这些线程可以共享进程中的资源。

进程间通信

  iOS 中大概有8种进程间通信的方式。

Port

  在 App1 内启动服务,App2 通过 ip 和 port 来访问,进行通信,不过此种方法需要两个 App 的进程都在存活状态,而且 iOS 系统只会给每个TCP在后台600秒的网络通信时间,600秒后 APP 会进入休眠状态。此处推荐一个 App 内搭建服务的框架 CocoaHTTPServer。

URL Scheme

  在利用 URL Scheme 打开 App 的时候,可以传递参数。打开 App 之前需要调用 canOpenURL: 方法查询,App 是否存在,但是从 iOS 9 开始需要在源 App 的 info.plist 中配置 LSApplicationQueriesSchemes 才可以调用canOpenURL: 方法,OpenURL: 方法不受影响。

Keychain

  iOS 系统的 Keychain 是一个安全的存储容器,它本质上就是一个sqllite数据库,它的位置存储在 /private/var/Keychains/keychain-2.db,不过它所保存的所有数据都是经过加密的,可以用来为不同的 App 保存敏感信息,比如用户名,密码等。iOS 系统自己也用 Keychain 来保存 VPN 凭证和 Wi-Fi 密码。它是独立于每个 App 的沙盒之外的,所以即使 App 被删除之后,Keychain 里面的信息依然存在。
  基于安全和独立于 App 沙盒的两个特性,Keychain 主要用于给 App 保存登录和身份凭证等敏感信息,这样只要用户登录过,即使用户删除了 App 重新安装也不需要重新登录。
  Keychain 用于 App 间通信的一个典型场景就是统一账户登录平台。使用同一个账号平台的多个 App,只要其中一个 App 用户进行了登录,其他 App 就可以实现自动登录不需要用户多次输入账号和密码。一般开放平台都会提供登录SDK,在这个SDK内部就可以把登录相关的信息都写到Keychain中,这样如果多个App都集成了这个SDK,那么就可以实现统一账户登录了。
  iOS 9 之后禁止获取 UDID 的 App 上架,可以利用 UUID 存储 keychain 作为唯一的标示, Keychain 的使用比较简单,使用 iOS 系统提供的类 KeychainItemWrapper,并通过 Keychain access groups 就可以在 App 之间共享Keychain中的数据的数据了,也可以使用框架 SAMKeychain。

UIPasteboard

  UIPasteboard 是剪切板功能,每一个App都可以去访问系统剪切板,而且 iOS 的控件 UITextView、UITextField 、UIWebView,长按就会出现复制、剪切、选中、全选、粘贴等功能,这个就是利用了系统剪切板功能来实现的,所以就能够通过系统剪贴板进行App间的数据传输了。典型的使用场景就是淘宝的淘口令。

UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = @"粘贴板测试文字";

UIDocumentInteractionController

  UIDocumentInteractionController 主要是用来实现同设备上App之间的共享文档,以及文档预览、打印、发邮件和复制等功能。UIDocumentInteractionController 对象要保证不被销毁,否则会程序报错:'UIDocumentInteractionController has gone away prematurely!'

self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"free_resume" ofType:@"html" inDirectory:@"awesomeResume/free"]]];
self.documentInteractionController.delegate = self;
[self.documentInteractionController presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];

AirDrop / UIActivityViewController

  通过 UIActivityViewController 的方法也可以唤起 AirDrop,进行数据交互,iOS并没有直接提供 AirDrop 的实现接口,上个方法同样也支持 AirDrop 的方式分享数据。

UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:@[@"123"] applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];

App Groups

   App Group 用于同一个开发团队开发的 App 之间,共享同一份读写空间,进行数据共享。也可用来实现同一个团队的多个 App 的单点登录。实现细节:App之间的数据共享——App Group的配置

线程

维基百科:线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

线程间通信

   在子线程进行耗时操作,主线程间刷新UI,就是经常见到的线程间通讯场景。线程间通信的方式主要有如下

NSThread

   NSThread 是经过苹果封装后,并且完全面向对象的。所以你可以直接操控线程对象,非常直观和方便。实际上使用也比较少,使用频率较多的是 GCD 以及 NSOperation。

// 子线程耗时操作
[self performSelectorInBackground:@selector(downloadData:) withObject:urlString];

// 去主线程刷新 UI
[self performSelectorOnMainThread:@selector(updateTextLabel:) withObject:textString waitUntilDone:NO];

- (void)updateTextLabel:(NSString *)textString
{
    self.textLabel.text = @"test";
}

GCD

   GCD(Grand Central Dispatch)伟大的中央调度系统,是苹果为多核并行运算提出的C语言并发技术框架。GCD 会自动利用更多的 CPU 内核。会自动管理线程的生命周期(创建线程,调度任务,销毁线程等)。只需要告诉 GCD 想要如何执行什么任务,不需要编写任何线程管理代码。

// 去主线程刷新 UI
dispatch_async(dispatch_get_main_queue(), ^{
        self.textlabel.text = @"test";
    });

NSOperation

   NSOperation 是苹果推荐使用的并发技术,相比GCD,NSOperation的使用更加简单,NSOperation的使用常常是配合NSOperationQueue来进行的。

// 子线程耗时操作
[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        [self downloadData:urlString];
}];

// 去主线程刷新 UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.textLabel.text = @"test";
    }];

线程池

维基百科:线程池(thread pool):一种线程使用模式。 线程过多会带来调度开销,进而影响缓存局部性和整体性能。 而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。 这避免了在处理短时间任务时创建与销毁线程的代价。

   线程池的执行流程:首先,启动若干数量的线程,并让这些线程处于睡眠状态。然后,当客户端有新的请求时,线程池会唤醒某一个睡眠线程,让它来处理客户端的请求。最后,当请求处理完毕,线程又处于睡眠状态。所以在并发的时候,同时能有多少线程在跑是有线程池的线程缓存数量决定的。
   GCDNSOperation 的线程池都默认存储 64 个线程,而 NSOperation 可以设置 maxConcurrentOperationCount ,但是设置超过 64 没有效果。YYDispatchQueuePool 支持使用更多线程来进行并发。

你可能感兴趣的:(多线程的理解)