語言:Swift3.1
|| Object-C
(本文使用Swift3.1)
作用:提高效率,同時處理多個task。
工具:xcode8.3.2
系統(tǒng):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??靜態(tài)方法實例化
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
需要結(jié)合NSOperationQueue
實現(xiàn)多線程編程。
初始化方式:
1??使用NSInvocationOperation
(由于swift中無此不安全的類。所以次數(shù)直接上代碼)
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(refreshUI:) object:imgUrl];
//[invocationOperation start];//會在主線程執(zhí)行
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的子類實現(xiàn)
//創(chuàng)建一個自定義的類繼承于Operation,重寫main方法,因為線程開始會在內(nèi)部調(diào)用這個方法
@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
同步 | 異步 | |
---|---|---|
串行隊列 | 在主線程,任務(wù)一個個執(zhí)行,阻塞主線程 | 任務(wù)一個個執(zhí)行,不阻塞主線程 |
并行隊列 | 在主線程,由于只有一個線程,所以一個個執(zhí)行,阻塞主線程 | 很多線程,并發(fā)執(zhí)行 |
創(chuàng)建隊列
在Swift3.0中對GCD進行了封裝 使用DispatchQueue來進行GCD的操作,OC中繼續(xù)使用dispatch_queue_xxxxx
類似C的寫法。
①主隊列(串行)(只用于刷新UI等操作)
let queue=DispatchQueue.main
②自定義一個隊列(可以為串行,可以為并行)
//最簡單的初始化隊列方式,為串行,優(yōu)先級默認,label為唯一標識符。
let quque = DispatchQueue.init(label: "test.jp.Queue")
//為串行,優(yōu)先級utility,label為唯一標識符。
let quque1=DispatchQueue.init(label: "test.jp.Queue", qos: .utility)
//為并行隊列,優(yōu)先級utility
let quque2=DispatchQueue.init(label: "", qos: .utility, attributes: .concurrent)
③全局并發(fā)隊列,默認的全局并發(fā)隊列,一般并發(fā)都可以使用
let queue = DispatchQueue.global()
創(chuàng)建任務(wù)
①同步任務(wù)(很容易造成死鎖)
let quque = DispatchQueue.init(label: "test.jp.Queue")
quque.sync {
print("hanihao")
}
②異步任務(wù)
let quque1=DispatchQueue.init(label: "test.jp.Queue", qos: .utility)
quque1.async {
print("nihao!!!")
}
手動觸發(fā)隊列(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()
}
延遲執(zhí)行
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
場景:在所有任務(wù)完成之后需要進行某些操作時使用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("全部加載完畢")
}
// 永久等待,直到所有任務(wù)執(zhí)行結(jié)束,中途不能取消,阻塞當前線程(不推薦使用)
group.wait()
print("組中任務(wù)全部完畢?。?!")
特別注意
①更新UI一樣要在主線程。
②并發(fā)隊列和串行隊列的區(qū)別,本質(zhì)上即為線程數(shù)量的區(qū)別,串行隊列為在一個線程中序列執(zhí)行,并發(fā)隊列為在多個線程中一起執(zhí)行。
一些簡單的示例代碼已經(jīng)上傳碼云
地址: swift多線程Demo
更多功能請查看詳細API。