一、多线程概述

  • 程序、进程、线程

    • 程序:由源代码生成的可执行应用。(例如:QQ.app)
    • 进程:一个正在运行的程序可以看做一个进程。(例如:正在运行的QQ就是一个进程),进程拥有独立运行所需的全部资源。
    • 线程:程序中独立运行的代码段。(例如:接收QQ消息的代码)

  一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。

  • 单线程

    • 每个正在运行的程序(即进程),至少包含一个线程,这个线程叫主线程。
    • 主线程在程序启动时被创建,用于执行main函数。
    • 只有一个主线程的程序,称作单线程程序。
    • 在单线程程序中,主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行。
  • 多线程
    • 拥有多个线程的程序,称作多线程程序。
    • iOS允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称作子线程。
    • 可以根据需要开辟若干子线程
    • 子线程和主线程 都是 独立的运行单元,各自的执行互不影响,因此能够并发执行。
  • 单线程、多线程区别
    • 单线程程序:只有一个线程,即主线程,代码顺序执行,容易出现代码阻塞(页面假死)。
    • 多线程程序:有多个线程,线程间独立运行,能有效的避免代码阻塞,并且提高程序的运行性能。
    • 注意:iOS中关于UI的添加和刷新必须在主线程中操作。

二、iOS平台下的多线程

  • iOS多线程实现种类

    • NSThread
    • NSOperationQueue
    • NSObject
    • GCD

三、NSThread

  • NSThread是一个轻量级的多线程,它有以下两种创建方法

    方法 功能
    - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument 初始化一个子线程,但需要手动开启
    + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument 初始化一个子线程并自动开启
    -start 开启子线程
    -cancel 取消当前子线程,不是真正的取消,而是给子线程发送了一个“取消”消息,标记为canceled
    +exit

    直接将线程退出

    • 第一种:手动开辟一个子线程

       - (void)viewDidLoad {
      #pragma mark - NSThread手动开辟子线程
      // 参数1: target
      // 参数2: 方法
      // 参数3: 要传的参数
      NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(sayHello:) object:@"说你好!"];
      #pragma mark - 启动子线程
      [thread start]; // 判断一个线程是否正在执行
      NSLog(@"是否正在执行%d",[thread isExecuting]);
      // 判断一个线程是否完成了任务(是否执行完毕)
      NSLog(@"是否执行完毕%d", [thread isFinished]); #pragma mark - 释放子线程的两种方式
      // 第一种:取消线程,不是真正的取消,而是给子线程发送了一个“取消”消息,标记为canceled
      // 判断线城是否被标记为canceled
      // NSLog(@"%d", [thread isCancelled]);
      // [thread cancel];
      // // 第二种:直接将线程退出
      // [NSThread exit]; } - (void)sayHello:(NSString *)hello {
      NSLog(@"%@", hello);
      // 打印当前线程
      NSLog(@"当前线程:%@", [NSThread currentThread]);
      NSLog(@"主线程:%@", [NSThread mainThread]);
      }

      Thread手动开辟一个子线程

    开辟子线程成功

    • 第二种:

       - (void)viewDidLoad {
      #pragma mark - NSThread自动开辟子线程
      // 线程自动开启,不需要创建NSThread的对象
      // 与手动开启线程的方法相比,target 和 selector 两个参数顺序颠倒
      [NSThread detachNewThreadSelector:@selector(sayHello:) toTarget:self withObject:@"说你好!"];
      } - (void)sayHello:(NSString *)hello {
      NSLog(@"%@", hello);
      // 打印当前线程
      NSLog(@"当前线程:%@", [NSThread currentThread]);
      NSLog(@"主线程:%@", [NSThread mainThread]);
      }

      Thread自动开辟子线程

  • 开辟子线程成功
  • 其他方法
  • 注意:
    • 每个线程都维护着与自己对应的NSAutoreleasePool对象,将其放在线程栈的栈顶。当线程结束时,会清空自动释放池。
    • 为保证对象的及时释放,在多线程方法中需要添加自动释放池。
    • 在应用程序打开的时候,系统会自动为主线程创建一个自动释放池。
    • 我们手动创建的子线程需要我们手动添加自动释放池。

四、NSObject实现异步后台执行

 - (void)viewDidLoad {
#pragma mark - NSObject开辟子线程
/**
* 开启线程的方式之二:NSObject
*/
// 使用performSelectorInBackground开辟子线程
// 参数1:方法
// 参数2:要传的参数
[self performSelectorInBackground:@selector(sayHello:) withObject:@"说你好!"];
self.view.backgroundColor = [UIColor yellowColor]; } - (void)sayHello:(NSString *)hello {
NSLog(@"%@", hello);
// 打印当前线程
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]); // 回到主线程修改view的背景颜色
// 参数1:方法
// 参数2:要传的参数
// 参数3:是否等待子线程完成后再进入主线程
[self performSelectorOnMainThread:@selector(changeColor) withObject:nil waitUntilDone:NO];
} - (void)changeColor {
self.view.backgroundColor = [UIColor cyanColor];
// 打印当前线程
NSLog(@"==当前线程:%@", [NSThread currentThread]);
NSLog(@"==主线程:%@", [NSThread mainThread]);
}

NSObject异步后台执行,开辟子线程

开辟子线程成功

NSThread和NSObject结合使用:同步请求延迟加载图片

 @interface ViewController ()
/// 声明一个ImageView用来显示图片
@property (nonatomic, strong) UIImageView *showImageView;
/// 声明一个NSData类型的数据用于接收图片的数据
@property (nonatomic, strong) NSData *imageData;
@end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// 创建imageView
_showImageView = [[UIImageView alloc] initWithFrame:CGRectMake(, , , )];
_showImageView.backgroundColor = [UIColor greenColor];
[self.view addSubview:_showImageView]; } #pragma mark - 触发子线程去加载数据
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self performSelectorInBackground:@selector(loadImageData) withObject:nil];
} // 加载图片数据
- (void)loadImageData {
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]);
NSURL *url = [NSURL URLWithString:@"http://img4q.duitang.com/uploads/item/201506/13/20150613185209_nHy5E.jpeg"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.imageData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// 创建主线程用于刷新UI
[self performSelectorOnMainThread:@selector(renovateUI) withObject:nil waitUntilDone:YES]; } // 主线程刷新UI
- (void)renovateUI {
// 安全判断
if ([NSThread mainThread]) {
_showImageView.image = [UIImage imageWithData:self.imageData];
}
}
@end

同步请求实现延迟加载图片

点击触发事件,开辟子线程成功,在主线程中刷新UI,图片显示成功

五、NSOperation和NSOperationQueue

  • NSOperation

    • NSOperation类,在MVC中属于M,是用来封装单个任务相关的代码和数据的抽象类
    • 因为它是抽象的,不能够直接使用这个类,而是使用子类( NSInvocationOperation或NSBlockOperation )来执行实际任务。
    • NSOperation(含子类),只是一个操作,本身无主线程、子线程之分,可在任意线程中使用。通常与NSOperationQueue结合使用。
  • NSInvocationOperation
    • NSInvocationOperation是NSOperation的子类
    • 封装了执行操作的target和要执行的action。
 - (void)viewDidLoad {
/**
* NSOperation不能直接进行多线程的创建,需要借助:NSOperationQueue。
NSOperation的子类本身和多线程没有任何关系,它只是封装了一定的代码段和数据去实现一个功能。
在单独使用NSOperation的子类去创建线程的时候,实际上线程没有真正被创建。
*/
// 使用NSOperation的第一个子类去创建子线程 -- NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(sayHello:) object:@"

UI进阶 多线程的更多相关文章

  1. UI进阶 科大讯飞(2) 语音合成(文字转换成语音)

    科大讯飞开放平台.SDK下载.添加静态库.初始化见UI进阶 科大讯飞(1) 语音听写(语音转换成文字) 实现语音合成 功能实现步骤: 导入头文件 创建文字识别对象 指定文字识别后的回调代理对象 开启文 ...

  2. android UI进阶之用【转】

    android UI进阶之用ViewPager实现欢迎引导页面 摘要: ViewPager需要android-support-v4.jar这个包的支持,来自google提供的一个附加包.大家搜下即可. ...

  3. UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

    这篇博客的代码是直接在上篇博客的基础上增加的,先给出部分代码,最后会给出能实现简单功能的完整代码. UI进阶 即时通讯之XMPP登录.注册 1.好友列表 初始化好友花名册 #pragma mark - ...

  4. Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask

    多线程一直是初学者最抵触的东西,如果你想进阶的话,那必须闯过这道难关,特别是多线程中Thread.Runnable.Callable.Future.FutureTask这几个类往往是初学者容易搞混的. ...

  5. UI:多线程 、用GCD创建线程

    什么是应用(程序):就是我们编写的代码编译后生成的app文件 进程:凡是一个运行的程序都可以看作为一个进程,如打开的多个 word,就可以认为是一个进程的多个线程. 线程:至少有一个线程就是主线程,网 ...

  6. Android进阶——多线程系列之异步任务AsyncTask的使用与源码分析

    AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并主线程中更新UI,通过AsyncTask可以更加方便执行后台任务以及在主线程中访问UI ...

  7. UI进阶

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  8. iOS开发——UI进阶篇(十五)Quartz2D介绍

    一.Quartz2D简介 1.什么是Quartz2DQuartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作绘制图形 : 线条\三角形\矩形\圆\弧等绘制文字绘 ...

  9. iOS开发——UI进阶篇(七)程序启动原理、打电话、发短信

    一.Info.plist常见的设置 1.建立一个工程后,会在Supporting files文件夹下看到一个“工程名-Info.plist”的文件,该文件对工程做一些运行期的配置,非常重要,不能删除 ...

随机推荐

  1. 华为P6-U06 ROOT

    移动.联通.电信版P6均可成功的EMUI3.0开发版/稳定版 ROOT... - P6/P6s 花粉俱乐部 http://cn.club.vmall.com/forum.php?mod=viewthr ...

  2. editplus的配置文件来支持sql语法高亮【转】

      editplus默认是没有sql语法高亮的,原因是它的内部没有sql.stx的这样一个语法文件 我们自己在 EditPlus 的安装目录下面新建一个文件名为sql.stx,然后打开editplus ...

  3. 【Oracle连接字符串】【Oracle Net Manager 服务命名配置】【PL/SQL 登陆数据库】

    连接数据库的几个重要参数: 1. 登陆用户名:user: 2. 登录密码:password: 3. 存放数据库的服务器地址(server_ip)和端口(server_port): 4. 数据库名(db ...

  4. ssh-keygen的使用方法

    一.概述 1.就是为了让两个linux机器之间使用ssh不需要用户名和密码.采用了数字签名RSA或者DSA来完成这个操作 2.模型分析 假设 A (192.168.20.59)为客户机器,B(192. ...

  5. 1521. War Games 2(线段树解约瑟夫)

    1521 根据区间和 来确定第k个数在哪 #include <iostream> #include<cstdio> #include<cstring> #inclu ...

  6. 函数fsp_alloc_seg_inode_page

    分配一个新的inode page /**********************************************************************//** Allocat ...

  7. JavaScript NodeList和Array

    原文引用脚本之家作者:Jeff Wong,谢谢大神提供资源 在Web前端编程中,我们通常会通过document.getElementsByTagName或者document.getElementsBy ...

  8. Ajax时代 SQL注入依然是隐患

    许多网站程序在编写时,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患.用户可以提交一段数据库查询代码(一般是在浏览器地址栏进行,通过正常的www端口访问),根据程序返回的结果,获得某些想得 ...

  9. Hibernate4.x之映射关系--多对多

    n-n的关联关系分为以下两类: 1.单向n-n关联关系: n-n的关联必须使用连接表 与1-n映射类似,必须为set集合元素添加key子元素,指定CATEGORIES_ITEMS表中参照CATEGOR ...

  10. gdi写的2048

    //-------------------------------------------[头文件及引用]----------------------------------------------- ...