Swift 网络请求工具类
2022-12-12 本文已影响0人
_浅墨_
一、首先定义 API 类:
import Foundation
import UIKit
// 声明 APIDelegate 回调方法
protocol APIDelegate: AnyObject {
func loginFailed(error: Error)
func loginSucceeded(userId: String)
func announcementsFailed(error: Error)
func announcementsLoaded(announcements: [Announcement])
func orgLoaded(org: [Employee])
func orgFailed(error: Error)
func eventsLoaded(events: [Event])
func eventsFailed(error: Error)
func productsLoaded(products: [Product])
func productsFailed(error: Error)
func purchasesLoaded(purchases: [PurchaseOrder])
func purchasesFailed(error: Error)
func userLoaded(user: UserInfo)
func userFailed(error: Error)
}
class API {
// 声明 server 地址与端口, 如 "http://localhost:8080/"
let server = AppDelegate.configuration.server
let session: URLSession
weak var delegate: APIDelegate?
var token: Token?
init() {
session = URLSession(configuration: .default)
}
func login(username: String, password: String) {
let eventsEndpoint = server + "api/users/login"
let eventsURL = URL(string: eventsEndpoint)!
var urlRequest = URLRequest(url: eventsURL)
urlRequest.httpMethod = "POST"
let data = "\(username):\(password)".data(using: .utf8)!
let basic = "Basic \(data.base64EncodedString())"
urlRequest.addValue(basic, forHTTPHeaderField: "Authorization")
let task = session.dataTask(with: urlRequest) { data, _, error in
guard let data = data else {
if error != nil {
DispatchQueue.main.async {
self.delegate?.loginFailed(error: error!)
}
}
return
}
let decoder = JSONDecoder()
if let token = try? decoder.decode(Token.self, from: data) {
self.handleToken(token: token)
} else {
do {
let error = try decoder.decode(APIError.self, from: data)
DispatchQueue.main.async {
self.delegate?.loginFailed(error: error)
}
} catch {
DispatchQueue.main.async {
self.delegate?.loginFailed(error: error)
}
}
}
}
task.resume()
}
func handleToken(token: Token) {
self.token = token
Logger.logDebug("user \(token.user.id)")
DispatchQueue.main.async {
self.delegate?.loginSucceeded(userId: token.user.id.uuidString)
}
}
func logout() {
token = nil
delegate = nil
UIApplication.appDelegate.showLogin()
}
//swiftlint:disable identifier_name
func submitPO(po: PurchaseOrder) throws {
let url = URL(string: server + "api/" + "purchases")!
var request = URLRequest(url: url)
if let token = token?.token {
let bearer = "Bearer \(token)"
request.addValue(bearer, forHTTPHeaderField: "Authorization")
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let coder = JSONEncoder()
coder.dateEncodingStrategy = .iso8601
let data = try coder.encode(po)
request.httpBody = data
let task = loadTask(
request: request,
success: self.poSuccess,
failure: self.delegate?.purchasesFailed(error:))
task.resume()
}
private func poSuccess(po: PurchaseOrder) {
getPurchases()
}
private func request(_ endpoint: String) -> URLRequest {
let url = URL(string: server + "api/" + endpoint)!
var request = URLRequest(url: url)
if let token = token?.token {
let bearer = "Bearer \(token)"
request.addValue(bearer, forHTTPHeaderField: "Authorization")
}
return request
}
func loadTask<T: Decodable>(
request: URLRequest,
success: ((T) -> Void)?,
failure: ((Error) -> Void)?
) -> URLSessionTask {
return session.dataTask(with: request) { data, _, error in
guard let data = data else {
if error != nil {
DispatchQueue.main.async {
failure?(error!)
}
}
return
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let items = try? decoder.decode(T.self, from: data) {
DispatchQueue.main.async {
success?(items)
}
} else {
do {
let error = try decoder.decode(APIError.self, from: data)
DispatchQueue.main.async {
failure?(error)
}
} catch {
DispatchQueue.main.async {
failure?(error)
}
}
}
}
}
func getAnnouncements() {
let req = request("announcements")
let task = loadTask(
request: req,
success: self.delegate?.announcementsLoaded(announcements:),
failure: self.delegate?.announcementsFailed(error:))
task.resume()
}
func getOrgChart() {
let req = request("employees")
let task = loadTask(
request: req,
success: self.delegate?.orgLoaded(org:),
failure: self.delegate?.orgFailed(error:))
task.resume()
}
func getEvents() {
let req = request("events")
let task = loadTask(
request: req,
success: self.delegate?.eventsLoaded(events:),
failure: self.delegate?.eventsFailed(error:))
task.resume()
}
func getProducts() {
let req = request("products")
let task = loadTask(
request: req,
success: self.delegate?.productsLoaded(products:),
failure: self.delegate?.productsFailed(error:))
task.resume()
}
func getPurchases() {
let req = request("purchases")
let task = loadTask(
request: req,
success: self.delegate?.purchasesLoaded(purchases:),
failure: self.delegate?.purchasesFailed(error:))
task.resume()
}
func getUserInfo(userID: String) {
let req = request("users/\(userID)")
let task = loadTask(
request: req,
success: self.delegate?.userLoaded(user:),
failure: self.delegate?.userFailed(error:))
task.resume()
}
}
二、使用方法:
- 在 AppDelegate 声明
// 声明变量
static var configuration: Configuration!
var api: API!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 初始化变量
AppDelegate.configuration = Configuration.load()
api = API()
return true
}
- 其中 Configuration:
import Foundation
struct Configuration: Codable {
struct UI: Codable {
struct Button: Codable {
let cornerRadius: Double
let borderWidth: Double
}
let button: Button
}
struct BusinessRules: Codable {
let maxPOExpense: Double
}
let server: String
let debug: Bool
let ui: UI
let rules: BusinessRules
}
// MARK: - Local Settings
extension Configuration {
var firstDayOfWeek: DaysOfWeek {
if UserDefaults.standard.object(forKey: "firstDayOfWeek") != nil {
return DaysOfWeek(rawValue: UserDefaults.standard.integer(forKey: "firstDayOfWeek"))!
}
return .sunday
}
}
extension Configuration {
//swiftlint:disable force_try
static func load() -> Configuration {
let url = Bundle.main.url(forResource: "configuration", withExtension: "json")!
let data = try! Data(contentsOf: url)
let decoder = JSONDecoder()
return try! decoder.decode(Configuration.self, from: data)
}
}
- 在 controller 中使用:
var api: API { return (UIApplication.shared.delegate as! AppDelegate).api }
let skin: Skin = .login
override func viewDidLoad() {
super.viewDidLoad()
api.delegate = self
Styler.shared.style(background: view, buttons: [signInButton], with: skin)
}