目前网上检索到的关于Swift的REST API Call实现很多已经在swift6之后算是过时了的,Swift6强化了并发安全,以及URLsession API也相应增加了async版本(旧版本使用callback),更modern的方法是使用async/await以及Task来构建REST API Call
以下均使用URLsession进行REST API Call
在旧版Swift中, Get接口是这么call的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func fetchPage (completion : @escaping (Result <PageData , Error >) -> Void ) { let url = URL (string: "http://127.0.0.1:8080/community/page/get" )! URLSession .shared.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(error)) return } guard let data = data else { completion(.failure(URLError (.badServerResponse))) return } do { let result = try JSONDecoder ().decode(PageData .self , from: data) completion(.success(result)) } catch { completion(.failure(error)) } }.resume() }
大量使用了回调函数。 另外值得说的是在Swift6中xcode默认会给没有显式隔离的代码视作@MainActor,也就是默认跑主线程,所以在老式写法里对于let result = try JSONDecoder().decode(PageData.self, from: data)这里要在 PageData 的结构体上标注一个nonisolated
Swift6以后,新式Get Call 的async/await写法是这样的
1 2 3 4 5 func fetchPage () async throws -> PageData { let url = URL (string: "http://127.0.0.1:8080/community/page/get" )! let (data, _ ) = try await URLSession .shared.data(from: url) return try JSONDecoder ().decode(PageData .self , from: data) }
wrap的时候可以通过Task来执行它
1 2 3 4 5 6 7 8 func load () { Task { let newPageData = try await fetchPage() ··· ······ ········· } }
同样的这是Swift6之后现代版的Post Call
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func createTopic (title : String , content : String , time : Int64 ) async throws -> Topic { let newTopic = Topic ( id: nil , title: title, content: content, create_time: time ) guard let url = URL (string: "http://127.0.0.1:8080/community/page/addtopic" ) else { throw URLError (.badURL) } var request = URLRequest (url: url) request.httpMethod = "POST" request.setValue("application/json" , forHTTPHeaderField: "Content-Type" ) request.httpBody = try JSONEncoder ().encode(newTopic) let (data, response) = try await URLSession .shared.data(for: request) guard let httpResponse = response as? HTTPURLResponse , 200 ..< 300 ~= httpResponse.statusCode else { throw URLError (.badServerResponse) } return try JSONDecoder ().decode(Topic .self , from: data) }
wrap之后用Task执行也是和get同理