【愚公系列】《移动端AI应用开发》027-iOS端应用开发(网络通信与API集成)

💎【行业认证·权威头衔】

✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家

✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主

✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者

🏆【荣誉殿堂】

🎖 连续三年蝉联"华为云十佳博主"(2022-2024)

🎖 双冠加冕CSDN"年度博客之星TOP2"(2022&2023)

🎖 十余个技术社区年度杰出贡献奖得主

📚【知识宝库】

覆盖全栈技术矩阵:

◾ 编程语言:.NET/Java/Python/Go/Node...

◾ 移动生态:HarmonyOS/iOS/Android/小程序

◾ 前沿领域:物联网/网络安全/大数据/AI/元宇宙

◾ 游戏开发:Unity3D引擎深度解析

文章目录

  • 🚀前言
  • 🚀一、网络通信与API集成
    • [🔎6.2.1 NSURLSession与网络请求](#🔎6.2.1 NSURLSession与网络请求)
    • [🔎6.2.2 JSON 解析与 Swift Codable](#🔎6.2.2 JSON 解析与 Swift Codable)
    • [🔎6.2.3 网络安全与HTTPS请求](#🔎6.2.3 网络安全与HTTPS请求)

🚀前言

本章深入探讨了iOS端应用开发的关键技术与实现方法,重点介绍了如何将DeepSeek 的强大AI能力集成到iOS应用中。通过详细的步骤和代码示例,本章阐明了如何在iOS平台上配置和使用DeepSeekSDK,如何与后端进行高效的数据交互,以及如何处理多种AI任务。结合iOS平台的开发特点,优化了性能、网络请求和用户体验,使得AI应用能够在iOS设备上高效、稳定地运行。

🚀一、网络通信与API集成

本节聚焦于iOS应用中的网络通信与API集成,详细讲解了如何通过网络请求与后端服务器进行高效数据交互。本节介绍了常用的iOS网络库,如URLSession,并结合具体的代码示例,展示了如何实现API的调用、响应处理及错误管理。通过精确控制网络请求的生命周期和优化请求参数,本节为开发者提供了高效、安全的数据传输方案。此外,还探讨了如何与DeepSeek API进行集成,确保AI模型与iOS应用的无缝连接。

🔎6.2.1 NSURLSession与网络请求

NSURLSession是iOS和macOS中处理网络请求的核心类之一,提供了基于HTTP、HTTPS、FTP等协议的网络请求功能。它被广泛应用于数据下载、上传以及与远程API交互。相比于旧版的NSURLConnection,NSURLSession在后台任务和并发操作方面提供了更强大的功能,支持同步和异步方式执行网络请求。NSURLSession的使用非常灵活,支持三种主要任务类型:数据任务、下载任务和上传任务。NSURLSession的核心概念是会话,每个NSURLSession对象管理着一个独立的网络会话,负责发送请求、接收响应、处理数据传输等操作。通过NSURLSessionConfiguration类,可以配置不同的会话行为,如指定请求头、缓存策略和连接超时等。

本节将结合一个真实的应用场景,展示如何使用NSURLSession执行一个简单的网络请求,获取远程数据,并解析JSON响应。我们将使用NSURLSession的dataTask方法发起异步请求,获取API的数据,并在响应返回时进行处理。

【例6-3】 展示如何在iOS应用中使用NSURLSession进行网络请求、处理响应并解析JSON数据。我们将向一个假设的API发送GET请求,获取数据并展示在应用的界面中。

swift 复制代码
import UIKit

// 定义数据模型,用于解析JSON响应
struct Post: Codable {
    let userId: Int
    let id: Int
    let title: String
    let body: String
}

class ViewController: UIViewController {
    var dataLabel: UILabel!
    var fetchButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // 设置UI元素
        setupUI()
    }

    func setupUI() {
        // 设置Label以显示从网络获取的数据
        dataLabel = UILabel()
        dataLabel.frame = CGRect(x: 20, y: 100, width: 300, height: 100)
        dataLabel.text = "Data will be shown here."
        dataLabel.numberOfLines = 0
        dataLabel.textAlignment = .center
        view.addSubview(dataLabel)

        // 设置按钮以触发网络请求
        fetchButton = UIButton(type: .system)
        fetchButton.frame = CGRect(x: 20, y: 250, width: 300, height: 40)
        fetchButton.setTitle("Fetch Data", for: .normal)
        fetchButton.addTarget(self, action: #selector(fetchData), for: .touchUpInside)
        view.addSubview(fetchButton)
    }

    @objc func fetchData() {
        let urlString = "https://jsonplaceholder.typicode.com/posts/1"
        guard let url = URL(string: urlString) else {
            print("Invalid URL")
            return
        }

        let session = URLSession.shared
        let task = session.dataTask(with: url) { data, response, error in
            // 处理错误
            if let error = error {
                print("Network error: \(error.localizedDescription)")
                return
            }

            // 确保响应成功
            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                print("Failed to receive valid response")
                return
            }

            // 解析JSON数据
            if let data = data {
                do {
                    let post = try JSONDecoder().decode(Post.self, from: data)
                    DispatchQueue.main.async {
                        // 更新UI
                        self.dataLabel.text = "Title: \(post.title) \nBody: \(post.body)"
                    }
                } catch {
                    print("Failed to decode JSON: \(error)")
                }
            }
        }
        // 启动网络请求任务
        task.resume()
    }
}

// AppDelegate和其他必要的配置
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let viewController = ViewController()
        window?.rootViewController = viewController
        window?.makeKeyAndVisible()
        return true
    }
}

代码说明如下:

  1. 数据模型Post 是一个结构体,符合 Codable 协议,用于解析JSON响应中的数据。这个模型包含了四个字段:userIdidtitlebody,这些字段与从API返回的数据结构相对应。
  2. UI设计UILabel 用于显示从网络获取的内容,UIButton 用于触发网络请求。在UI上,按钮单击后会调用 fetchData 方法来发起网络请求。
  3. NSURLSession和网络请求URLSession.shared.dataTask(with: url) 方法发起一个GET请求,从指定的URL获取数据。在这里,我们使用了 jsonplaceholder.typicode.com 提供的一个免费的模拟API,来获取一个简单的JSON响应。网络请求是异步进行的,dataTask 完成后,回调的闭包会处理响应数据。如果请求成功并返回200状态码,我们会尝试解析JSON并将结果显示在UI上。
  4. JSON解析 :使用 JSONDecoder().decode() 将从网络请求获得的数据解码为 Post 模型的实例。如果解码成功,我们将更新UI,显示帖子标题和内容。如果失败,会打印错误信息。
  5. UI更新 :网络请求和JSON解析是异步执行的,因此我们通过 DispatchQueue.main.async 确保在主线程中更新UI。这是必须的,因为所有UI更新都应在主线程进行。

在模拟器或真实设备上运行时,单击 Fetch Data 按钮后,应用会发送一个请求到 jsonplaceholder.typicode.com,获取ID为1的帖子数据。控制台输出以下信息:

复制代码
Network error: The operation couldn't be completed. (NSURLErrorDomain error -1009.)

如果网络连接正常且API返回有效响应,控制台输出以下内容:

复制代码
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit\nsuscipit...et id est laborum

UILabel 将更新为:

复制代码
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit\nsuscipit...et id est laborum

本节演示了如何使用NSURLSession进行网络请求,并使用JSONDecoder解析API返回的JSON数据。在实际的iOS开发中,NSURLSession提供了高效、灵活的方式来处理网络请求。结合UI更新机制,开发者可以实现流畅的用户体验和强大的数据交互功能。通过这种方式,开发者能够轻松地集成远程API,并通过网络获取和展示数据。

🔎6.2.2 JSON 解析与 Swift Codable

在现代iOS开发中,网络请求往往会返回JSON格式的数据。为了高效地处理这些数据并将其转化为Swift对象,Swift提供了 Codable 协议,它结合了 EncodableDecodable 协议,能够简化JSON的编码与解码操作。Codable 协议允许将对象转换为JSON格式,也可以将JSON格式的数据转换回对象,这对于与RESTful API的交互尤其重要。

Swift的 Codable 协议是处理JSON数据的主要工具,它利用 JSONDecoderJSONEncoder 来进行数据的序列化和反序列化。JSONDecoder 将JSON数据解析为对应的Swift对象,而 JSONEncoder 则将Swift对象转化为JSON格式。

在实际开发中,开发者通常会将API返回的数据映射到自定义的Swift结构体或类中。每个字段会对应JSON中的键,这些结构体或类需要遵循 Codable 协议,以便能通过 JSONDecoderJSONEncoder 进行转换。

【例6-4】 展示如何在iOS应用中使用 Codable 来解析JSON数据。示例中,我们将从一个模拟API获取JSON数据,并解析为Swift对象。使用 Post 结构体来映射API返回的数据。

swift 复制代码
import UIKit

// 定义数据模型Post,符合Codable协议
struct Post: Codable {
    let userId: Int
    let id: Int
    let title: String
    let body: String
}

class ViewController: UIViewController {
    var dataLabel: UILabel!
    var fetchButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // 设置UI元素
        setupUI()
    }

    func setupUI() {
        // 设置显示数据的UILabel
        dataLabel = UILabel()
        dataLabel.frame = CGRect(x: 20, y: 100, width: 300, height: 100)
        dataLabel.text = "Data will be shown here."
        dataLabel.numberOfLines = 0
        dataLabel.textAlignment = .center
        view.addSubview(dataLabel)

        // 设置按钮来触发网络请求
        fetchButton = UIButton(type: .system)
        fetchButton.frame = CGRect(x: 20, y: 250, width: 300, height: 40)
        fetchButton.setTitle("Fetch Data", for: .normal)
        fetchButton.addTarget(self, action: #selector(fetchData), for: .touchUpInside)
        view.addSubview(fetchButton)
    }

    @objc func fetchData() {
        let urlString = "https://jsonplaceholder.typicode.com/posts/1"
        guard let url = URL(string: urlString) else {
            print("Invalid URL")
            return
        }

        let session = URLSession.shared
        let task = session.dataTask(with: url) { data, response, error in
            // 处理错误
            if let error = error {
                print("Network error: \(error.localizedDescription)")
                return
            }

            // 确保响应成功
            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                print("Failed to receive valid response")
                return
            }

            // 解析JSON数据
            if let data = data {
                do {
                    let post = try JSONDecoder().decode(Post.self, from: data)
                    DispatchQueue.main.async {
                        // 更新UI
                        self.dataLabel.text = "Title: \(post.title) \nBody: \(post.body)"
                    }
                } catch {
                    print("Failed to decode JSON: \(error)")
                }
            }
        }
        // 启动网络请求任务
        task.resume()
    }
}

// AppDelegate和其他必要的配置
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let viewController = ViewController()
        window?.rootViewController = viewController
        window?.makeKeyAndVisible()
        return true
    }
}

代码说明如下:

  1. 数据模型PostPost 是一个符合 Codable 协议的结构体,用于表示从API获取的数据。Codable 协议使得该结构体可以方便地进行JSON的编码和解码。Post 模型包括了 userIdidtitlebody 字段,这些字段对应API返回的JSON中的键。
  2. UI设计 :创建了一个 UILabel 来显示从API返回的数据,UIButton 则触发网络请求。用户单击按钮时,会调用 fetchData() 方法从API获取数据。
  3. 网络请求与JSON解析NSURLSession 用于发送GET请求获取API数据。dataTask 方法异步执行请求,当响应到达时,回调闭包会处理响应。使用 JSONDecoder 来解析返回的JSON数据,将其转换为 Post 对象。decode(_:from:) 方法将JSON数据映射到 Post 结构体中,并返回解析后的对象。如果解析成功,更新UI显示数据。
  4. 主线程UI更新 :由于网络请求是异步执行的,UI更新必须在主线程中完成。通过 DispatchQueue.main.async 确保UI更新操作在主线程执行。
  5. 错误处理 :网络请求和JSON解析过程中,可能会出现错误。在代码中,我们通过 do-catch 语句捕获解析错误,并在控制台输出错误信息。

在模拟器或物理设备上运行时,单击 Fetch Data 按钮后,应用会发送GET请求到 jsonplaceholder.typicode.com,获取ID为1的帖子数据。控制台输出如下信息:

复制代码
Network error: The operation couldn't be completed. (NSURLErrorDomain error -1009.)

如果网络连接正常且API返回有效响应,控制台输出如下信息:

复制代码
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit\nsuscipit...et id est laborum

UILabel 会更新为:

复制代码
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit\nsuscipit...et id est laborum

本节展示了如何在iOS应用中使用Swift的 Codable 协议来解析API返回的JSON数据。通过结合 NSURLSession 进行网络请求,并使用 JSONDecoder 将JSON数据映射到自定义数据模型,开发者可以轻松地处理和展示从网络获取的数据。Codable 使得JSON解析变得简单、高效,同时保证了数据类型的安全性。通过这些技术,开发者能够更好地与RESTful API进行交互,并处理复杂的数据交互任务。

🔎6.2.3 网络安全与HTTPS请求

随着移动应用的广泛使用,网络安全变得越来越重要。特别是对于涉及用户数据交换的应用,使用安全的通信协议(如HTTPS)至关重要。HTTPS是基于SSL/TLS(安全套接层/传输层安全性)协议的HTTP协议,它为在互联网上传输的数据提供了加密和身份验证功能,确保数据的机密性、完整性和身份验证。

iOS中,所有网络请求默认通过HTTPS进行加密处理,确保在数据传输过程中的安全性。NSURLSession 是iOS中进行网络请求的主要工具,可以与HTTPS一起使用来确保网络通信的安全性。通过设置适当的SSL/TLS验证,iOS设备可以防止中间人攻击和数据泄露。

在进行HTTPS请求时,iOS通过 URLSessionURLRequest 进行网络连接。请求会自动进行SSL/TLS握手,通过服务器的数字证书来验证通信双方的身份,从而确保与服务器的安全连接。此外,开发者可以通过自定义SSL证书验证和配置请求头等方式,进一步增强通信的安全性。

下面是一个使用 NSURLSession 进行HTTPS请求的完整示例。示例中,我们将向一个支持HTTPS的API发送请求,获取JSON数据,并处理SSL/TLS验证。

【例6-5】 展示如何在iOS应用中进行HTTPS请求,配置SSL/TLS证书验证,处理可能的网络安全问题,确保请求过程的安全性。

swift 复制代码
import UIKit

// 定义数据模型Post,符合Codable协议
struct Post: Codable {
    let userId: Int
    let id: Int
    let title: String
    let body: String
}

class ViewController: UIViewController {
    var dataLabel: UILabel!
    var fetchButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // 设置UI元素
        setupUI()
    }

    func setupUI() {
        // 设置显示数据的UILabel
        dataLabel = UILabel()
        dataLabel.frame = CGRect(x: 20, y: 100, width: 300, height: 100)
        dataLabel.text = "Data will be shown here."
        dataLabel.numberOfLines = 0
        dataLabel.textAlignment = .center
        view.addSubview(dataLabel)

        // 设置按钮来触发网络请求
        fetchButton = UIButton(type: .system)
        fetchButton.frame = CGRect(x: 20, y: 250, width: 300, height: 40)
        fetchButton.setTitle("Fetch Data", for: .normal)
        fetchButton.addTarget(self, action: #selector(fetchData), for: .touchUpInside)
        view.addSubview(fetchButton)
    }

    @objc func fetchData() {
        let urlString = "https://jsonplaceholder.typicode.com/posts/1"
        guard let url = URL(string: urlString) else {
            print("Invalid URL")
            return
        }

        // 自定义NSURLSession配置来处理SSL证书
        let sessionConfig = URLSessionConfiguration.default
        sessionConfig.timeoutIntervalForRequest = 30
        sessionConfig.timeoutIntervalForResource = 60

        let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
        let task = session.dataTask(with: url) { data, response, error in
            // 处理错误
            if let error = error {
                print("Network error: \(error.localizedDescription)")
                return
            }

            // 确保响应成功
            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                print("Failed to receive valid response")
                return
            }

            // 解析JSON数据
            if let data = data {
                do {
                    let post = try JSONDecoder().decode(Post.self, from: data)
                    DispatchQueue.main.async {
                        // 更新UI
                        self.dataLabel.text = "Title: \(post.title)\nBody: \(post.body)"
                    }
                } catch {
                    print("Failed to decode JSON: \(error)")
                }
            }
        }
        // 启动网络请求任务
        task.resume()
    }
}

// NSURLSessionDelegate协议实现SSL/TLS验证
extension ViewController: URLSessionDelegate {
    // 此方法用于验证服务器证书
    func urlSession(_ session: URLSession,
                    didReceive challenge: URLAuthenticationChallenge,
                    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        // 忽略自签名证书验证,仅作为示例
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            if let trust = challenge.protectionSpace.serverTrust {
                let credential = URLCredential(trust: trust)
                completionHandler(.useCredential, credential)
            }
        } else {
            completionHandler(.cancelAuthenticationChallenge, nil)
        }
    }
}

// AppDelegate和其他必要的配置
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let viewController = ViewController()
        window?.rootViewController = viewController
        window?.makeKeyAndVisible()
        return true
    }
}

代码说明如下:

  1. HTTPS请求 :使用 NSURLSession 来执行HTTPS请求。我们创建了一个自定义的 URLSessionConfiguration,并设置了请求超时参数。请求通过 dataTask 发起并处理响应。
  2. SSL/TLS证书验证 :在实际应用中,HTTPS请求会涉及SSL/TLS证书验证。在这个示例中,使用了 URLSessionDelegate 协议中的 urlSession(_:didReceive:completionHandler:) 方法来处理SSL证书验证。为了简化代码示例,我们允许任何有效的服务器证书(忽略了自签名证书的验证)。NSURLAuthenticationMethodServerTrust 表示服务器证书的验证机制,URLCredential 对象用于提供一个有效的证书凭证,completionHandler(.useCredential, credential) 允许继续使用该证书建立连接。
  3. 网络请求和JSON解析 :通过 URLSession 发起GET请求,成功接收到响应后,使用 JSONDecoder 解析返回的JSON数据。解析后的数据将更新到UI的 UILabel 中。
  4. UI更新与异步操作URLSession 的请求是异步进行的,因此UI的更新(例如更新 UILabel 的文本)必须通过 DispatchQueue.main.async 在主线程中执行,以避免UI更新引起的问题。

在应用程序中,单击 Fetch Data 按钮后,应用将发送HTTPS请求获取数据。以下是控制台的输出结果(假设网络正常并且API返回有效响应):

复制代码
Network error: The operation couldn't be completed. (NSURLErrorDomain error -1009.)

如果网络连接正常且API返回有效响应:

复制代码
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit\nsuscipit...et id est laborum

并且 UILabel 的文本将更新为:

复制代码
Title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Body: quia et suscipit\nsuscipit...et id est laborum

本节展示了如何在iOS应用中使用 NSURLSession 执行HTTPS请求,并处理SSL/TLS证书验证。通过 URLSessionDelegate 协议,可以自定义处理SSL证书验证,确保与服务器的安全连接。结合JSON解析,开发者能够高效、可靠地与远程API进行交互,保障数据的安全性与完整性。