语言:Swift3.1
|| Object-C
(本文使用Swift3.1)
作用:提高效率,同时处理多个task。
工具:xcode8.3.2
系统:MAC OX
iOS中的各种多线程
NSThread
每个NSThread
对象都是一个线程。比较轻量级,无法做到复杂的操作。
初始化方式
1️⃣普通实例化
let thread: Thread = Thread.init(target: self, selector: #selector(joinImage(imageURL:)), object: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg"))
2️⃣静态方法实例化
Thread.detachNewThreadSelector(#selector(joinImage(imageURL:)), toTarget: self, with: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg"))
3️⃣隐式方法实例化
self.performSelector(inBackground: #selector(joinImage(imageURL:)), with: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg"))
具体工程代码如下:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func generalMethod(_ sender: Any) {
let thread: Thread = Thread.init(target: self, selector: #selector(joinImage(imageURL:)), object: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg"))
thread.start()
}
@IBAction func staticMethod(_ sender: Any) {
Thread.detachNewThreadSelector(#selector(joinImage(imageURL:)), toTarget: self, with: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg"))
}
@IBAction func ImplicitMethod(_ sender: Any) {
self.performSelector(inBackground: #selector(joinImage(imageURL:)), with: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg"))
}
@objc private func joinImage(imageURL: URL) {
let data: Data = try!Data.init(contentsOf: imageURL)
let image: UIImage? = UIImage.init(data: data)
if let imageisOK = image {
self.performSelector(onMainThread: #selector (refreshUI(image:)), with: imageisOK, waitUntilDone: true)
} else {
print("图片加载失败!!!!")
}
}
@objc private func refreshUI(image: UIImage) {
imageView.image = image;
}
NSThread
还提供多种简单方法,详细查看其API,不再介绍。
NSOperation
需要结合NSOperationQueue
实现多线程编程。
初始化方式:
1️⃣使用NSInvocationOperation
(由于swift中无此不安全的类。所以次数直接上代码)
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(refreshUI:) object:imgUrl];
//[invocationOperation start];//会在主线程执行
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:invocationOperation];
2️⃣使用BlockOperation
初始化
let blockOperation = BlockOperation.init {
self.joinImage(imageURL: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg")!)
}
let operationQueue = OperationQueue.init()
operationQueue.addOperation(blockOperation)
3️⃣自定义一个Operation的子类实现
//创建一个自定义的类继承于Operation,重写main方法,因为线程开始会在内部调用这个方法
@objc protocol loadImageProtocol {
}
class MyOperation: Operation {
var urlImage: URL = URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg")!
weak var deleagte: loadImageProtocol?
override func main() {
if self.isCancelled {
return
}
if let dele = deleagte {
let controller = dele as! ViewController
controller.joinImage(imageURL: urlImage)
}
}
}
使用如下:
//初始化自定义的类,并且指定代理最后加入队列即可。
let myOp: MyOperation = MyOperation.init()
myOp.deleagte = self
let operationQueue = OperationQueue.init()
operationQueue.addOperation(myOp)
GCD
同步 | 异步 | |
---|---|---|
串行队列 | 在主线程,任务一个个执行,阻塞主线程 | 任务一个个执行,不阻塞主线程 |
并行队列 | 在主线程,由于只有一个线程,所以一个个执行,阻塞主线程 | 很多线程,并发执行 |
创建队列
在Swift3.0中对GCD进行了封装 使用DispatchQueue来进行GCD的操作,OC中继续使用dispatch_queue_xxxxx
类似C的写法。
①主队列(串行)(只用于刷新UI等操作)
let queue=DispatchQueue.main
②自定义一个队列(可以为串行,可以为并行)
//最简单的初始化队列方式,为串行,优先级默认,label为唯一标识符。
let quque = DispatchQueue.init(label: "test.jp.Queue")
//为串行,优先级utility,label为唯一标识符。
let quque1=DispatchQueue.init(label: "test.jp.Queue", qos: .utility)
//为并行队列,优先级utility
let quque2=DispatchQueue.init(label: "", qos: .utility, attributes: .concurrent)
③全局并发队列,默认的全局并发队列,一般并发都可以使用
let queue = DispatchQueue.global()
创建任务
①同步任务(很容易造成死锁)
let quque = DispatchQueue.init(label: "test.jp.Queue")
quque.sync {
print("hanihao")
}
②异步任务
let quque1=DispatchQueue.init(label: "test.jp.Queue", qos: .utility)
quque1.async {
print("nihao!!!")
}
手动触发队列(iOS 10.0以上)
var quque: DispatchQueue?
if #available(iOS 10.0, *) {
let quque = DispatchQueue.init(label: "com.jp.queue", qos: .default, attributes: [.concurrent, .initiallyInactive])
quque.async {
for i in 0...100 {
print("\(i)")
}
}
}
//开始队列
if #available(iOS 10.0, *) {
quque?.activate()
}
延迟执行
quque.asyncAfter(deadline: .now() + 0.88, execute: {
for i in 0...100 {
print("\(i)")
}
})
使用DispatchWorkItem
DispatchWorkItem
是一个代码块,具体用法很简单,看下面代码
let myqueue = DispatchQueue.init(label: "myqueue")
let workitem = DispatchWorkItem.init {
for _ in 0...100 {
print("DispatchWorkItem的使用!!!")
}
}
myqueue.async(execute: workitem)
使用DispatchGroup
场景:在所有任务完成之后需要进行某些操作时使用DispatchGroup
。
示例:
let group = DispatchGroup.init()
let queue = DispatchQueue.global()
queue.async(group: group) {
self.createImage(imageView: self.imageView1, url: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg")!)
}
queue.async(group: group) {
self.createImage(imageView: self.imageView2, url: URL.init(string: "http://img02.tooopen.com/images/20140127/sy_54827852166.jpg")!)
}
// 不阻塞主线程
group.notify(queue: DispatchQueue.global()) {
print("全部加载完毕")
}
// 永久等待,直到所有任务执行结束,中途不能取消,阻塞当前线程(不推荐使用)
group.wait()
print("组中任务全部完毕!!!")
特别注意
①更新UI一样要在主线程。
②并发队列和串行队列的区别,本质上即为线程数量的区别,串行队列为在一个线程中序列执行,并发队列为在多个线程中一起执行。
一些简单的示例代码已经上传码云
地址: swift多线程Demo
更多功能请查看详细API。