107 lines
5.3 KiB
Swift
107 lines
5.3 KiB
Swift
//
|
||
// RESTManager.swift
|
||
// IOS_study
|
||
//
|
||
// Created by CC-star on 2025/7/3.
|
||
//
|
||
|
||
import Foundation
|
||
|
||
final class RESTManager {
|
||
static let shared = RESTManager()
|
||
private init() {}//让RESTManager只在这个class在内部被实例化,不在外部实例化,只能在这个作用域里面被调用
|
||
//通过REST API获取一条数据
|
||
func findOne<T: Decodable>(form urlStr: String) async throws -> T {
|
||
guard let url = URL(string: urlStr) else { throw URLError(.badURL) }
|
||
|
||
var request = URLRequest(url: url)
|
||
request.httpMethod = "GET"
|
||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||
request.setValue(kAppID, forHTTPHeaderField: "X-LC-Id")
|
||
request.setValue(kAppKey, forHTTPHeaderField: "X-LC-Key")
|
||
|
||
let (data, response) = try await URLSession.shared.data(for: request)
|
||
//print(String(data: data, encoding: .utf8) ?? "Invalid data")
|
||
|
||
guard let httpRespsonse = response as? HTTPURLResponse, 200..<300 ~= httpRespsonse.statusCode else { throw URLError(.badServerResponse) }
|
||
|
||
let decoder = JSONDecoder()
|
||
//decoder.keyDecodingStrategy = .convertFromSnakeCase//数据库字段是下划线写法的时候
|
||
//把数据库里面的时间戳字符串转换成Date类型(了解)
|
||
decoder.dateDecodingStrategy = .custom { decoder -> Date in
|
||
let container = try decoder.singleValueContainer()
|
||
let dateString = try container.decode(String.self)
|
||
let isoFormatter = ISO8601DateFormatter()
|
||
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] // 支持毫秒
|
||
if let date = isoFormatter.date(from: dateString) { return date }
|
||
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date format: \(dateString)")
|
||
}
|
||
return try decoder.decode( T.self, from: data)
|
||
}
|
||
|
||
|
||
//通过REST API获取数组数据
|
||
func find<T: Decodable>(form urlStr: String) async throws ->[T] {
|
||
guard let url = URL(string: urlStr) else { throw URLError(.badURL) }
|
||
|
||
var request = URLRequest(url: url)
|
||
request.httpMethod = "GET"
|
||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||
request.setValue(kAppID, forHTTPHeaderField: "X-LC-Id")
|
||
request.setValue(kAppKey, forHTTPHeaderField: "X-LC-Key")
|
||
|
||
let (data,_) = try await URLSession.shared.data(for: request)
|
||
//print(String(data: data, encoding: .utf8) ?? "Invalid data")
|
||
|
||
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||
let results = json["results"] as? [[String: Any]] else {
|
||
throw URLError(.cannotParseResponse)
|
||
}
|
||
|
||
let decoder = JSONDecoder()
|
||
//decoder.keyDecodingStrategy = .convertFromSnakeCase//数据库字段是下划线写法的时候
|
||
//把数据库里面的时间戳字符串转换成Date类型(了解)
|
||
decoder.dateDecodingStrategy = .custom { decoder -> Date in
|
||
let container = try decoder.singleValueContainer()
|
||
let dateString = try container.decode(String.self)
|
||
let isoFormatter = ISO8601DateFormatter()
|
||
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] // 支持毫秒
|
||
if let date = isoFormatter.date(from: dateString) { return date }
|
||
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date format: \(dateString)")
|
||
}
|
||
|
||
let tData = try JSONSerialization.data(withJSONObject: results)
|
||
return try decoder.decode([T].self, from: tData)
|
||
}
|
||
|
||
|
||
//通过REST API上传数据
|
||
func save<T: Encodable>(to urlStr: String, object: T) async throws {//T:代表通用类型,泛型,Encodable编码
|
||
guard let url = URL(string: urlStr) else { throw NetworkError.invalidURL//抛出问题 -> 无效网址
|
||
}//有值则赋值给url,没有则进入else
|
||
|
||
var request = URLRequest(url: url)
|
||
request.httpMethod = "POST"
|
||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||
request.setValue(kAppID, forHTTPHeaderField: "X-LC-Id")
|
||
request.setValue(kAppKey, forHTTPHeaderField: "X-LC-Key")
|
||
|
||
let encoder = JSONEncoder()
|
||
// encoder.keyEncodingStrategy = .convertToSnakeCase//数据字段是下划线的写法的时候
|
||
request.httpBody = try encoder.encode(object)//注意:使用链接的方式请求LeanCloud REST需要去掉Date字段(或其他处理)
|
||
|
||
let (data, response) = try await URLSession.shared.data(for: request)//向服务器请求数据,并返回一个元组类型【一个数据,一个响应】
|
||
|
||
guard let httpRespsonse = response as? HTTPURLResponse else { throw NetworkError.notHTTPResponse }
|
||
|
||
if !(200..<300).contains(httpRespsonse.statusCode) {//如果不是 2开头的响应码 -> [200,300)
|
||
let errRespsonse = try JSONSerialization.jsonObject(with: data) as? [String: Any]//Any:字典类型
|
||
let errMsg = errRespsonse?["error"] as? String ?? "响应数据类型转换失败"
|
||
//如果errRespsonse没有值,则返回error
|
||
//如果上面的errRespsonse?["error"] as? String都不满足则返回:响应数据类型转换失败,【??】空壳运算符
|
||
|
||
throw NetworkError.requestFailed("错误码:\(httpRespsonse.statusCode),错误信息:\(errMsg)")
|
||
}
|
||
}
|
||
}
|