44

iOS多线程与网络

 5 years ago
source link: https://husteryp.github.io/2019/02/24/iOS多线程/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

iOS多线程编程各种方式总结

正文

一. 概述

iOS中多线程的实现方式有如下四种:

MrIRZvj.png!web

本文主要总结常用的两种方式

二. GCD

2.1 GCD概述

GCD即Grand Central Dispatch,是苹果公司为多核的并行运算提出的解决方案,能自动合理地利用多核CPU(比如双核、四核),同时还能自动管理线程的生命周期(创建线程、调度任务、销毁线程),不需要手动管理;由C语言实现

2.2 GCD使用

2.2.1 主要方法

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)
dispatch_async(queue, ^{
            // reading
        });
        dispatch_async(queue, ^{
            // reading
        });
        dispatch_barrier_sync(queue, ^{
            // writing
        });
        dispatch_async(queue, ^{
            // reading
        });
        dispatch_async(queue, ^{
            // reading
        });

2.2.2 队列

GCD中有两个重要的概念:任务和队列

  1. 任务有两种执行方式:同步执行和异步执行,他们之间的区别是否会创建新的线程
  2. 队列:用于存放任务。有两种队列, 串行队列和并行队列;区别如下:

FjUJnqu.png!web

可以通过如下方式获取或者创建队列:

dispatch_queue_create
dispatch_get_global_queue
dispatch_get_main_queue
// 自己创建队列:第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列;
// 第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列

  //串行队列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
  //并行队列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
// 全局并行队列:
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

2.2.3 队列组(Dispatch Group)

可用于实现当并行执行block时,监听所有block执行结束

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, queue, ^{
            NSLog(@"Block 1");
        });
        dispatch_group_async(group, queue, ^{
            NSLog(@"Block 2");
        });
        dispatch_group_async(group, queue, ^{
            NSLog(@"Block 3");
        });
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"Done");
        });

应用举例:分别执行两个耗时的操作,等两个异步操作都执行完之后,回到主线程执行操作;如果想要高效实现上述需求,可用队列组;如下

dispatch_group_t group =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 等前面的异步操作都执行完毕后,回到主线程...
});

2.2.4 其他

  • 延迟执行:通过 dispatch_walltime 生成绝对时间
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC); // ull表示:unsigned long long 
        dispatch_after(time, dispatch_get_main_queue(), ^{
            
});
  • dipatch_apply:相当于dipatch_sync和dispatch group的关联API,该函数将指定的block追加到指定的queue中,并等待全部处理执行结束;其也会阻塞直到执行完毕,可用其替代for循环
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, queue, ^(size_t index) { // index表示当前索引,自动增加
      NSLog(@"%zu", index);
    });
    NSLog(@"Done"); // 最后执行
  • dispatch_suspend / dispatch_resume:用于挂起和恢复queue

  • Dispatch Semaphore:计数为0时等待,计数为1或大于1时,减1而不是等待

  • dispatch_once:保证在应用程序中只执行一次指定处理的API

  • Dispatch IO:当读取大文件时,将文件分成合适的大小并使用Global Queue读取的话,会快很多,如果想尝试提高文件读取速度,可以使用Dispatch IO

2.2.5 备注

在iOS6.0之前,在GCD中每当使用带creat单词的函数创建对象之后,都应该对其进行一次release操作。在iOS6.0之后,GCD被纳入到了ARC的内存管理机制中,在使用GCD的时候我们就像对待普通OC对象一样对待GCD,因此不再需要我们调用release方法

三. NSOperation

  1. 本身是个抽象类,需要使用其子类:NSInvocationOperation,NSBlockOperation,或自定义子类
  2. 默认情况下,调用 NSInvocationOperation 的 start 方法并不会开一条新线程去执行,而是在当前线程执行;需要把 NSOperation 放到一个 NSOperationQueue 中才会执行异步操作
  3. NSBlockOperation:只要 NSBlockOperation 封装的操作数 > 1,就会异步执行操作
  4. 支持取消,暂停和恢复,还可以设置依赖来保证执行顺序,如 [operationB addDependency:operationA]; // 操作B依赖于操作A ;还可以在不同 queue 的 NSOperation 之间创建依赖关系
  5. 支持监听一个操作的执行完毕:通过 completionBlocksetCompletionBlock 实现

四. 网络请求

网络请求常用类:

  1. NSURL:请求地址
  2. NSURLRequest:一个NSURLRequest对象就代表一个请求,它包含的信息有:一个 NSURL 对象,请求方法,请求头,请求体,请求超时等
  3. NSMutableURLRequest:NSURLRequest的子类
  4. NSURLConnection:负责发送请求;支持发送同步请求(sendSynchronousRequest)和异步请求(sendAsynchronousRequest);还可以设置代理监听网络请求过程(开始响应,接收数据,结束响应,请求出错)

第三方框架:

  1. ASIHttpRequest
  2. AFNetworking
  3. MKNetworkKit

iOS中发送 HTTP 请求的方案:

  • 苹果原生
    1. NSURLConnection:用法简单,坑较多
    2. NSURLSession:功能比 NSURLConnection 强大,苹果推荐使用(但是NSURLSessionTask是一个抽象类,本身不能使用,只能使用它的子类:NSURLSessionDataTask\NSURLSessionUploadTask\NSURLSessionDownloadTask)
    3. CFNetwork:NSURL*的底层实现,纯C语言

两种为NSURLConnection设置代理方式的区别:

//第一种设置方式:
    //通过该方法设置代理,会自动的发送请求
    // [[NSURLConnection alloc]initWithRequest:request delegate:self];

    //第二种设置方式:
    //设置代理,startImmediately为NO的时候,该方法不会自动发送请求
    NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
    //手动通过代码的方式来发送请求
    //注意该方法内部会自动的把connect添加到当前线程的RunLoop中在默认模式下执行
    [connect start];

五. 数据解析

Json解析(转OC数据类型):

  1. 第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)
  2. 苹果原生:NSJSONSerialization(性能最好)

7byaUbQ.png!web

XML解析:

  • 解析方式有两种:
    1. DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
    2. SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件
  • 解析API:
    1. 官方原生:NSXMLParser,SAX方式解析
    2. libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
    3. GDataXML:DOM方式解析,由Google开发,基于libxml2

六. RunLoop

RunLoop是iOS中比较重要的一点,较短篇幅无法讲完,后面有机会再另起新篇总结

七. 参考博客

  1. https://www.jianshu.com/p/0b0d9b1f1f19

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK