Day21 URLSession 01 - POST

URLSession

前言:
我们在开发专案时常常需要跟网路上的後台(Server)沟通互动,这就必须用到网路请求,我们会发送 request 给 Server,Server 会再回传 response来串接网路上Server 的API,而 iOS 在 iOS 9 之後使用NSURLSession实现网路请求,透过NSURLSessionURLSession物件建立一个请求Task,然後执行Task 即可,包括快取、多执行绪任务等 iOS 都已经在sdk 层面封装完毕

以下我们就来看看如何使用URLSession串接 RESTful API,我们用Reqres API 来示范,串接API 会使用到的Data Model 可以参考Codable JSON 教学

POST:建立资料

首先我们根据以上的Request Body 以及Response 建立关於Post Sample 的Model

User.swift

struct UserRequestBody: Encodable {
    var name: String
    var job: String
}

struct UserPostResponse: Decodable {
    var name: String
    var job: String
    var id: String?
    var dateCreated: Date?
    
    var modifiedId: String {
        if let newId = id {
            return newId
        } else {
            return "******"
        }
    }
    
    var modifiedDateCreated: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .medium
        if let newDate = dateCreated {
            return dateFormatter.string(from: newDate)
        } else {
            return "******"
        }
    }
    
    enum CodingKeys: String, CodingKey {
        case name
        case job
        case id
        case dateCreated = "createdAt"
    }
}

接着建立UserURLSession.swift来处理关於URLSession的事件

import Foundation

class UserURLSession {
    static let shared = UserURLSession()
    
    func userPostRequest(userRequestBody:UserRequestBody,completionHandler: @escaping (UserPostResponse) -> Void) {
        
        let url = URL(string: "https://reqres.in/api/users")!
        
        // MARK: URLRequest
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        
        guard let httpBody = try? JSONEncoder().encode(userRequestBody) else {
            print("Invalid httpBody")
            return
        }
        
        // MARK: Set httpBody
        request.httpBody = httpBody
        
        URLSession.shared.dataTask(with: request) {
            data, response, error in
            if let data = data {
                do {
                    let decoder = JSONDecoder()
                    
                    decoder.dateDecodingStrategy = .formatted(DateFormatter.customFormatter)
                    
                    let user = try decoder.decode(UserPostResponse.self, from: data)
                    
                    completionHandler(user)
                    
                }catch(let error) {
                    print(error.localizedDescription)
                }
            } else {
                print("No Data")
            }
        }.resume()
    }
}

extension DateFormatter {
    static let customFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.locale = Locale(identifier: "en_us_POSIX")
        return formatter
    }()
}

之後在View 设计画面并使用

POSTSampleView.swift

struct POSTSampleView: View {
    
    @State private var name = "Ryder"
    @State private var job = "Engineer"
    
    @State var user :UserPostResponse = UserPostResponse(name: "*****", job: "*****", id: nil, dateCreated: nil)
    
    var body: some View {
        NavigationView {
            VStack {
                List(){
                    Text("POST sample")
                    Section(header: Text("Request Data")) {
                        TextField("Name: ", text: $name)
                        TextField("Job: ", text: $job)
                    }
                }
                List() {
                    Section(header: Text("Response Data")) {
                        Text("Name: \(user.name)")
                        Text("Job: \(user.job)")
                        Text("ID: \(user.modifiedId)")
                        Text("Date created: \(user.modifiedDateCreated)")
                    }
                }
                .listStyle(GroupedListStyle())
                Button {
                    UserURLSession.shared.userPostRequest(userRequestBody: UserRequestBody(name: name, job: job)) { newUser in
                        DispatchQueue.main.async {
                            user = newUser
                        }
                    }
                    
                } label: {
                    Text("POST Request")
                }
                .padding()
                .foregroundColor(Color.white)
                .background(Color.green)
                .cornerRadius(8)
                
            }            
            .navigationBarTitleDisplayMode(.inline)
            .navigationTitle(Text("URLSession POST Sample"))
        }
        
    }
}

struct POSTSampleView_Previews: PreviewProvider {
    static var previews: some View {
        POSTSampleView()
    }
}

这边所有URLSession 的范例一起放在Github: URLSessionSample 供大家参考


<<:  Day21 Plugin 从零开始到上架 - 取得权杖(Android)

>>:  Day 24 - 继承家业

[DAY9] Boxenn 实作 Entity 与 Value Object

隆重介绍 Boxenn! 它是我们专门用来在 legacy code 中导入 DDD 的套件,之後会...

Two Sum 演算法初阶题,Ruby 30 天刷题修行篇第九话

大家好,我是阿飞,今天的题目是演算法初阶题目 Two Sum,让我们一起来看看: 题目来源 Code...

Day 24 : Jenkins 在Build完通知与好用套件

介绍Jenkins的章节即将进入尾声了。事实上你可能会想Jenkins默认介面这麽老气,怎麽就成为全...

Day05 - 今天只调了 VS Code 让 tab 为 2格 space

因为开启 Vue CLI 时有套用 ESLint,而他似乎希望我缩排为 2 space 所以将 VS...

D8 - 用 Swift 和公开资讯,打造投资理财的 Apps { 台股申购资讯实作.1 - 取得公开申购公告csv档 }

承上一篇,公开申购公告的纲页页面如下 依照我们会需要的栏位,我们的 model 如下 // // S...