在 iOS 中呼叫 Web API 的方式有五種不同類型,使用同步呼叫方式有一種,其餘四種為非同步呼叫,專案中要使用哪一種方式都可以,隨個人的風格偏好自由挑選。
程式碼中使用到的 url 變數,定義如下,這是我給的一個測試網址,其傳回內容為「hello everyone」,當然可以換成任何實際的網址。另外,範例程式碼並未加上任何的錯誤處理,一切都當作不會有錯誤或是 nil 發生。
let url = URL(string: "https://raw.githubusercontent.com/kirkchu/testdata/main/hello")!
Storyboard 專案
將一個 Label 元件拖放到預設的 ViewController 上,並設定 IBOutlet 名稱為 label。 然後拖放五個 Button 元件,IBAction 函數名稱無所謂,按下後分別用不同的方式呼叫 Web API。
第一種:同步呼叫
@IBAction func buttonSync(_ sender: Any) {
let html = try! String(contentsOf: url)
label.text = html
}
若呼叫後傳回的內容為 binary 格式(例如 jpeg、mp3…),將 String 型態換成 Data 型態即可。
第二種:使用 GCD 的非同步呼叫
@IBAction func buttonAsync_GCD(_ sender: Any) {
DispatchQueue.global().async {
let html = try! String(contentsOf: url)
DispatchQueue.main.async {
self.label.text = html
}
}
}
第三種:使用 URLSession 的 Closure 函數
@IBAction func buttonURLSession_Closure(_ sender: Any) {
URLSession.shared.dataTask(with: url) { data, response, error in
let html = String(data: data!, encoding: .utf8)
DispatchQueue.main.async {
self.label.text = html
}
}.resume()
}
第四種:使用 URLSession 的 async 函數
@IBAction func buttonURLSession_Async(_ sender: Any) {
Task {
let (data, _) = try await URLSession.shared.data(from: url)
let html = String(data: data, encoding: .utf8)
label.text = html
}
}
第五種:使用 Combine 框架
先在 ViewController.swift 中匯入 Combine 框架以及加上 cancellable 變數 。
import UIKit
import Combine
class ViewController: UIViewController {
var cancellable: AnyCancellable? = nil
呼叫方式如下。
@IBAction func buttonCombine(_ sender: Any) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.sink { value in
switch value {
case .finished:
break
case .failure(let error):
print(error)
}
} receiveValue: { (data, response) in
let html = String(data: data, encoding: .utf8)
DispatchQueue.main.async {
self.label.text = html
}
}
}
SwiftUI 專案
調整預設的 ContentView 如下,之後的幾種呼叫方式都是換掉 Button 元件中的內容。
struct ContentView: View {
@State var text = ""
var body: some View {
VStack {
Button("") {
// code here
}
Text(text)
.padding()
}
}
}
第一種:同步呼叫
Button("同步") {
text = try! String(contentsOf: url)
}
若傳回的內容為 binary 格式(例如 jpeg、mp3…),將 String 型態換成 Data 型態即可。
第二種:使用 GCD 的非同步呼叫
Button("非同步+GCD") {
DispatchQueue.global().async {
text = try! String(contentsOf: url)
}
}
第三種:使用 URLSession 的 Closure 函數
Button("URLSession + Closure") {
URLSession.shared.dataTask(with: url) { data, response, error in
text = String(data: data!, encoding: .utf8)!
}.resume()
}
第四種:使用 URLSession 的 async 函數
Button("URLSession + Async") {
Task {
let (data, _) = try await URLSession.shared.data(from: url)
text = String(data: data, encoding: .utf8)!
}
}
第五種:使用 Combine 框架
先在 ContentView 中匯入 Combine 框架,並且加上 cancellable 變數。
import Combine
struct ContentView: View {
@State var cancellable: AnyCancellable? = nil
呼叫方式如下。
Button("Combine") {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.sink { value in
switch value {
case .finished:
break
case .failure(let error):
print(error)
}
} receiveValue: { (data, response) in
text = String(data: data, encoding: .utf8)!
}
}