首页

如何请求 API 数据接口(HTTP Request)

By 前端达人
Published in C-高级进阶
August 07, 2022
1 min read
如何请求 API 数据接口(HTTP Request)

在创建应用程序时,我们通常通过 HTTP 请求的方式从 API 中获取一些数据。在 SwiftUI 中,您可以使用第三方插件(如 Swift-Request 或 Alamofire)来执行此操作,但创建一个自定义的 HTTP 请求函数非常容易。本篇文章我们将自定义一个HTTP请求函数,我们使用一个免费的 REST API。请求调用 /users 端点以获取 10 个用户的列表并将它们显示在我们的视图中。

创建 Network class 类

我们需要创建一个继承 ObservableObject 协议的类。通过使我们的类符合 ObservableObject,类中的更改将自动反映在我们的视图中。让我们创建一个 Network.swift 文件,我们将在其中调用 API。

// Network.swift

import SwiftUI

class Network: ObservableObject {

}

User model

接下来,我们将创建一个User model (用户模型)。通过这样做,我们可以使定义的变量符合用户数据类型。该模型还将允许我们将从 API 获得的 JSON 解码为用户数据类型。此外,我们可以通过简单地编写 user.name 来调用用户名的数据。

首先,我们需要知道我们获得的 JSON 数据的结构。我们可以前往https://jsonplaceholder.typicode.com/users 看看它的结构,如下图所示:

接口数据预览
接口数据预览

如上图所示,JSON 是一个对象数组。每个对象代表一个用户,它包含许多键值对。

回到我们的项目,我们需要创建一个包含所有这些键值对的结构。为了方便大家练习,小编已经为您创建了 User 模型,如下所示。只需创建一个新的 User.swift 文件,复制以下代码即可:

// User.swift

import Foundation

struct User: Identifiable, Decodable {
    var id: Int
    var name: String
    var username: String
    var email: String
    var address: Address
    var phone: String
    var website: String
    var company: Company

    struct Address: Decodable {
        var street: String
        var suite: String
        var city: String
        var zipcode: String
        var geo: Geo

        struct Geo: Decodable {
            var lat: String
            var lng: String
        }
    }

    struct Company: Decodable {
        var name: String
        var catchPhrase: String
        var bs: String
    }
}

该模型继承 Identifiable 和 Decodable 协议。Identifiable 表示每个项目都有一个唯一的 ID。Decodable 表示意味着它可以被解码——例如,我们可以将一个 JSON 对象转换成这个数据模型。

@Published variable

回到 Network.swift,我们需要在类中创建一个 @Published users 变量。变量的类型将是 Users 数组。我们将使用一个空数组来初始化变量。

// Network.swift

class Network: ObservableObject {
        @Published var users: [User] = []
}

通过接口请求数据

现在,我们需要创建 getUsers 函数来从 API 中获取用户,在 Network 类文件中创建函数。

// Network.swift

func getUsers() {
    guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { fatalError("Missing URL") }

    let urlRequest = URLRequest(url: url)

    let dataTask = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
        if let error = error {
            print("Request error: ", error)
            return
        }

        guard let response = response as? HTTPURLResponse else { return }

        if response.statusCode == 200 {
            guard let data = data else { return }
            DispatchQueue.main.async {
                do {
                    let decodedUsers = try JSONDecoder().decode([User].self, from: data)
                    self.users = decodedUsers
                } catch let error {
                    print("Error decoding: ", error)
                }
            }
        }
    }

    dataTask.resume()
}

在上面的代码中,首先我们确保有URL地址。使用这个 URL,我们正在创建一个 URLRequest,并将它传递给我们的 dataTask 变量中。

我们正在确保没有错误,并且我们确实得到了接口数据的请求。如果响应为 200 状态(表示接口正确得到了响应),我们会再次检查是否有数据。

然后,我们使用 JSONDecoder 对我们得到的 JSON 格式的数据进行解码,并将数据解码为一个用户数组。解码完成后,我们将其分配给我们在类顶部定义的 users 变量。

最后,我们使用 dataTask.resume() 恢复我们的 dataTask。

创建 environmentObject 对象

现在我们的函数已经创建好了,我们需要在 ProjectNameApp.swift 文件中添加我们的 Network 类作为 EnvironmentObject 。

// ProjectNameApp.swift

import SwiftUI

@main
struct ProjectNameApp: App {
    var network = Network()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(network)
        }
    }
}

在 ContentView 中,将 Network 添加为 EnvironmentObject。

// ContentView.swift

struct ContentView: View {
        @EnvironmentObject var network: Network

        // More code...
}

要预览数据,请记住在 ContentView 的预览中添加 environmentObject,就能在程序运行时,看到数据加载的效果了。

// ContentView.swift

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(Network())
    }
}

调用 getUsers 方法

在 body 方法中,我们添加 ScrollView 和 onAppear 方法,在 onAppear 调用 getUsers() 方法

// ContentView.swift

var body: some View {
        ScrollView {
                Text("All users")
                .font(.title).bold()
        }
        .onAppear {
                network.getUsers()
        }
}

循环显示 Users 数据

然后,只需遍历 network.users。我们将显示每个用户的 ID、姓名、电子邮件和电话。

VStack(alignment: .leading) {
    ForEach(network.users) { user in
        HStack(alignment:.top) {
            Text("\(user.id)")

            VStack(alignment: .leading) {
                Text(user.name)
                    .bold()

                Text(user.email.lowercased())

                Text(user.phone)
            }
        }
        .frame(width: 300, alignment: .leading)
        .padding()
        .background(Color(#colorLiteral(red: 0.6667672396, green: 0.7527905703, blue: 1, alpha: 0.2662717301)))
        .cornerRadius(20)
    }
}

注:如果您使用的是预览模式,请记住按预览播放按钮将会触发 API ,请求其中获取数据。如果您使用的是模拟器,结果应该会立即出现。

完整代码

到这里,我们就实现了一个完整的 HTTP 请求的例子,最后贴出完整的代码,方便大家归纳和使用:

Network.swift 文件

// Network.swift

import SwiftUI

class Network: ObservableObject {
    @Published var users: [User] = []

    func getUsers() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { fatalError("Missing URL") }

        let urlRequest = URLRequest(url: url)

        let dataTask = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
            if let error = error {
                print("Request error: ", error)
                return
            }

            guard let response = response as? HTTPURLResponse else { return }

            if response.statusCode == 200 {
                guard let data = data else { return }
                DispatchQueue.main.async {
                    do {
                        let decodedUsers = try JSONDecoder().decode([User].self, from: data)
                        self.users = decodedUsers
                    } catch let error {
                        print("Error decoding: ", error)
                    }
                }
            }
        }

        dataTask.resume()
    }
}

ContentView.swift 文件

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var network: Network

    var body: some View {
        ScrollView {
            Text("All users")
                .font(.title)
                .bold()

            VStack(alignment: .leading) {
                ForEach(network.users) { user in
                    HStack(alignment:.top) {
                        Text("\(user.id)")

                        VStack(alignment: .leading) {
                            Text(user.name)
                                .bold()

                            Text(user.email.lowercased())

                            Text(user.phone)
                        }
                    }
                    .frame(width: 300, alignment: .leading)
                    .padding()
                    .background(Color(#colorLiteral(red: 0.6667672396, green: 0.7527905703, blue: 1, alpha: 0.2662717301)))
                    .cornerRadius(20)
                }
            }

        }
        .padding(.vertical)
        .onAppear {
            network.getUsers()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(Network())
    }
}

最终在模拟器中运行我们的代码,你将会看到如下的效果:

案例效果
案例效果

版权声明

注:本文属于原创文章,版权属于「前端达人」公众号及 SwiftUI.cc 所有,谢绝一切形式的转载

更多精彩内容,请关注「前端达人」

欢迎关注「前端达人」
欢迎关注「前端达人」


Tags

#advanced#HTTP Request
Previous Article
如何处理 JSON 文件的数据(Data from JSON)
前端达人

前端达人

专注前端知识分享

Table Of Contents

1
创建 Network class 类
2
User model
3
@Published variable
4
通过接口请求数据
5
创建 environmentObject 对象
6
调用 getUsers 方法
7
循环显示 Users 数据
8
完整代码
9
版权声明

Related Posts

关于 WKWebView 的使用总结
August 12, 2022
1 min

前端学习站

前端达人官网VUE官网React官网TypeScript官网

公众号:前端达人

京ICP备16033841号-8