iOS开发

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()
  }
}

二、使用方法:

  1. 在 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
  }
  1. 其中 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)
  }
}

  1. 在 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)
  }
上一篇下一篇

猜你喜欢

热点阅读