iOS 网络请求: Alamofire 结合 ObjectMapper 实现自动解析

news2025/1/22 15:14:40

引言

在 iOS 开发中,网络请求是常见且致其重要的功能之一。从获取资料到上传数据,出色的网络请求框架能夠大大提升开发效率。

Alamofire 是一个极具人气的 Swift 网络请求框架,提供了便据的 API 以完成网络请求和响应处理。它支持多种请求类型,如 GET 和 POST,并且给予您便据的带容处理过滤器和返回数据解析的功能。

ObjectMapper 是一个强大的 Swift 数据映射工具,使用其提供的 Mappable 协议,可以将 JSON 数据自动映射到 Swift 模型中,大大简化解析代码和出错处理。

本文将介绍如何使用 Alamofire 和 ObjectMapper,完成 GET 和 POST 请求,并将返回数据自动解析为 Swift 模型。通过实战和代码示例,帮助您快速熟练这两种工具,从而提升开发效率。

Alamofire发起GET、POST请求

Alamofire为我们提供了十分简洁的数据请求方法,还可以根据数据的返回类型解析不同的响应体,我们以JSON格式为例。只需要设置请求地址、请求方式、请求参数、编码方式以及请求头。

GET请求

AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: endpoint.headers).responseJSON { (response) in
            switch response.result {
            case .success:
                if let json = response.value as? [String: Any] {
                    ...
                } else {
                    // 数据为空 或者格式不对
                    let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_dataFormat, userInfo: [NSLocalizedDescriptionKey: "数据为空或者格式不对"])
                }
            case .failure(let error):
                let mwError = MWNetError(error: error,isCanceled: error.isExplicitlyCancelledError)
                completion(nil, nil, mwError)
            }
        }

POST请求

AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: endpoint.headers).responseJSON { (response) in
            switch response.result {
            case .success:
                if let json = response.value as? [String: Any] {
                   ....
                } else {
                    // 数据为空 或者格式不对
                    let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_dataFormat, userInfo: [NSLocalizedDescriptionKey: "数据为空或者格式不对"])
  
                }
            case .failure(let error):
                let mwError = MWNetError(error: error,isCanceled: error.isExplicitlyCancelledError)
                mainThread(model: nil, data: nil, error: mwError, completion: completion)
            }
        }

ObjectMapper进行数据解析

使用ObjectMapper进行数据解析成模型时,需要模型遵循Mappable协议,并手动创建数据对应的键值映射。

假设有以下的json数据:

{
    "id": 123,
    "name": "John Doe",
    "email": "john.doe@example.com"
}

那我们需要可以创建一个对应的数据模型:

import ObjectMapper

class User: Mappable {
    var id: Int?
    var name: String?
    var email: String?

    required init?(map: Map) {}

    func mapping(map: Map) {
        id    <- map["id"]
        name  <- map["name"]
        email <- map["email"]
    }
}

然后借助Mapper实现解析:

func parseUserData(json: [String: Any]) {
    if let user = Mapper<User>().map(JSON: json) {
        print("User ID: \(user.id ?? 0)")
        print("Name: \(user.name ?? "No Name")")
        print("Email: \(user.email ?? "No Email")")
    } else {
        print("Failed to parse user data")
    }
}

// 示例调用
let jsonData: [String: Any] = [
    "id": 123,
    "name": "John Doe",
    "email": "john.doe@example.com"
]

parseUserData(json: jsonData)

Alamofire结合ObjectMapper实现接口数据自动解析

而在实际的项目开发中往往我们并不会直接使用Alamofire进行网络的请求,而是会进一步封装增加一层,在这一层中呢我们可以设置一些公共参数,公共请求头,请求加密处理,服务端环境切换等等等等工作,包括数据的处理和自动解析当然也可以在这一层来进行。

以我们当前的项目为例,为了处理网络的请求专门创建了一个名为MWNetworkHelper的类,它负责文件的上传、文件的下载、非加密的GET请求,非加密的POST请求,加密的GET请求、加密的POST请求,以及请求后的数据处理和错误处理。

接下来我们就以非加密的POST请求为例来分析Alamofire结合ObjectMapper实现接口数据自动解析。

项目中的所有请求通过MWNetworkHelper的类方法发送:

public class func request<T: Mappable>(endpoint: MWAPIProtocol, parameters: [String: Any]?,modelType:T.Type? = MWNetEmptyData.self, completion: ((_ model:T?,_ data:Any?, MWNetError?) -> Void)?) -> DataRequest?

该方法的具体实现如下:

    /// 发起请求
    /// - Parameters:
    /// - endpoint: 请求地址,枚举
    /// - parameters: 请求参数
    /// - completion: 请求完成回调
    /// - T: 返回数据模型
    /// - return: 请求
    @discardableResult
    public class func request<T: Mappable>(endpoint: MWAPIProtocol, parameters: [String: Any]?,modelType:T.Type? = MWNetEmptyData.self, completion: ((_ model:T?,_ data:Any?, MWNetError?) -> Void)?) -> DataRequest? {
        let completion = completion ?? {_,_,_ in }
        // 如果是断网状态直接返回
        if !MWNetworkManager.shared.isReachable {
            let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_noNetwork, userInfo: [NSLocalizedDescriptionKey: "网络不可用"])
            let mwError = MWNetError(error: error,isCanceled: false)
            MWToast.showToast("网络不可用")
            mainThread(model: nil, data: nil, error: mwError, completion: completion)
            return nil
        }
        
        if let encryEndpoint = endpoint as? MWAPIEncryEndpoint{
            return requestEncrypt(endpoint: encryEndpoint, parameters: parameters, modelType: modelType, completion: completion)
        } else if let normalEndpoint = endpoint as? MWAPINormalEndpoint {
            return requestNormal(endpoint: normalEndpoint, parameters: parameters, modelType: modelType, completion: completion)
        } else {
            fatalError("endpoint is not MWAPIProtocol")
        }
    }
  1. 该方法首先判断了网络状态,如果处于断网状态直接回调回error数据。
  2. 接下来根据枚举所属的类判断发起的是加密请求还是非加密请求。

加密请求和非加密请求都还会再次分割为GET请求和POST的请求,我们直接过渡到非加密的POST请求。

    /// 发起非加密的POST请求
    /// - Parameters:
    /// - endpoint: 请求地址,枚举
    /// - parameters: 请求参数
    /// - completion: 请求完成回调
    /// - T: 返回数据模型
    /// - return: 请求
    @discardableResult
    public class func requestNormalPOST<T: Mappable>(endpoint: MWAPINormalEndpoint, parameters: [String: Any]?, modelType:T.Type? = MWNetEmptyData.self, completion: @escaping (_ model:T?,_ data:Any?, MWNetError?) -> Void) -> DataRequest {
        MWLogHelper.debug("非加密POST=请求地址:\(endpoint.domain + endpoint.path) 请求参数:\(String(describing: parameters))", context: "Network")
        let url = endpoint.domain + endpoint.path
        return AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: endpoint.headers).responseJSON { (response) in
            switch response.result {
            case .success:
                if let json = response.value as? [String: Any] {
                    dealRequestJsonData(endpoint: endpoint, data: json, completion: completion)
                } else {
                    // 数据为空 或者格式不对
                    let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_dataFormat, userInfo: [NSLocalizedDescriptionKey: "数据为空或者格式不对"])
                    let mwError = MWNetError(error: error,isCanceled: false)
                    mainThread(model: nil, data: nil, error: mwError, completion: completion)
                }
            case .failure(let error):
                let mwError = MWNetError(error: error,isCanceled: error.isExplicitlyCancelledError)
                mainThread(model: nil, data: nil, error: mwError, completion: completion)
            }
        }
    }
  1. 利用Swift的特性我们创建了一个泛型,通过T:Mappable指定了返回数据模型必须遵循ObjectMapper的Mappable协议,确保可以进行JSON映射,灵活支持不同的返回类型。
  2. MWAPINormalEndpoint是一个非加密请求的枚举,枚举内包含了很多内容包括请求的域名或根据环境进行切换,包括具体的请求接口以及公共请求头等等信息。
  3. 对于一个成功的请求,调用dealRequestJsonData方法开始处理数据。
  4. 而对于一个失败的请求,我们直接回调回error信息。

对于数据处理的方法dealRequestJsonData,由于项目庞大的原因,它仍然包含了很多内容,但是我们可以把重点直接集中到简单的部分:

    /// 处理数据
    /// - Parameters:
    /// - data: 数据
    /// - completion: 完成回调
    /// - T: 返回数据模型
    private class func dealRequestJsonData<T: Mappable>(endpoint: MWAPIProtocol,data:[String:Any],modelType:T.Type? = nil,completion: @escaping (_ model:T?,_ data:Any?, MWNetError?) -> Void) {
        var data = data
        // 如果是加密数据
           ....

        if endpoint.isDirectParse {
            // 错误结果
            if let code = data["code"] as? Int {
                 ...
                return
            }
            // 直接解析
            let model = Mapper<T>().map(JSON: data)
            mainThread(model: model, data: data, error: nil, completion: completion)
        } else {
          ....

        }
    }
    
    /// 主线程回调
    /// - Parameters:
    /// - modelType: 数据模型类型
    /// - model: 数据模型
    /// - data: 数据
    /// - error: 错误
    /// - completion: 完成回调
    private class func mainThread<T: Mappable>(modelType:T.Type? = nil,model:T?,data:Any?,error:MWNetError?,completion: @escaping (_ model:T?,_ data:Any?, MWNetError?) -> Void) {
        DispatchQueue.main.async {
            completion(model, data, error)
        }
    }
  1. 因为服务端并不一定会只返回一种结构的数据格式,我们只考虑直接解析这一种。​​​​​​​
  2. 直接通过let model = Mapper<T>().map(JSON: data)获取到我们需要的数据模型。
  3. 在主线程中回调回数据。

结语

在现代 iOS 应用开发中,处理网络请求和数据解析是一项基础但极具挑战的任务。本文通过 Alamofire 和 ObjectMapper 的结合,展示了如何构建灵活且高效的网络请求与数据解析架构。从发起请求到解析数据,再到错误处理的全流程,我们看到了这两种工具如何相辅相成,极大提升了开发效率。

然而,开发并非一成不变,实际应用场景中,可能会涉及到更多复杂的需求,例如分页加载、文件上传、错误重试等。希望本篇内容为你的项目提供启发,也欢迎你探索和扩展 Alamofire 与 ObjectMapper 的更多潜力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280427.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面向对象编程——对象实例化

在python中&#xff0c;对象实例化是根据类的定义创建具体对象的过程。也就是将类当成模板&#xff0c;从而定义了对象的结构和行为&#xff0c;而实例化则是根据这个模板创建具体的对象实例。每个实例都有自己独立的状态&#xff0c;但是却共享类的结构和方法。 代码&#xff…

阿里云-银行核心系统转型之业务建模与技术建模

业务领域建模包括业务建模和技术建模&#xff0c;整体建模流程图如下&#xff1a; 业务建模包括业务流程建模和业务对象建模 业务流程建模&#xff1a;通过对业务流程现状分析&#xff0c;结合目标核心系统建设能力要求&#xff0c;参考行业建 模成果&#xff0c;形成结构化的…

Unreal Engine 5 C++ Advanced Action RPG 九章笔记

第九章 Hero Special Abilities 2-Challenges Ahead(前方的挑战) 本次章节主要解决三件问题 怒气能力特殊武器能力治疗石怒气能力 对于这个能力我们需要处理它的激活和持械状态,当没有怒气时应该取消该能力当这个能力激活时,我希望角色是进入无敌状态的,不会受到伤害怒气状…

cursor重构谷粒商城05——docker容器化技术快速入门【番外篇】

前言&#xff1a;这个系列将使用最前沿的cursor作为辅助编程工具&#xff0c;来快速开发一些基础的编程项目。目的是为了在真实项目中&#xff0c;帮助初级程序员快速进阶&#xff0c;以最快的速度&#xff0c;效率&#xff0c;快速进阶到中高阶程序员。 本项目将基于谷粒商城…

【FPGA】MIPS 12条整数指令【1】

目录 修改后的仿真结果 修改后的完整代码 实现bgtz、bltz、jalr 仿真结果&#xff08;有问题&#xff09; bltz------并未跳转&#xff0c;jCe&#xff1f; 原因是该条跳转语句判断的寄存器r7&#xff0c;在该时刻并未被赋值 代码&#xff08;InstMem修改前&#xff09; i…

洛谷题目:P2742 [USACO5.1] 圈奶牛Fencing the Cows /【模板】二维凸包 题解 (本题较难)

题目传送门&#xff1a;P2742 [USACO5.1] 圈奶牛Fencing the Cows /【模板】二维凸包 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 另&#xff1a;由于一些文章的疏忽&#xff0c;导致一些错别字&#xff0c;代码错误&#xff0c;公式错误导致大家的理解和误导&#xff0c;…

多线程之旅:线程安全问题

之前说到了多线程的创建和一些属性等等&#xff0c;接下来&#xff0c;就来讲讲多线程安全问题。 小编引入这段代码讲解下&#xff1a; public class Demo13 {public static int count0;public static void main(String[] args) throws InterruptedException {Thread t1new…

html学习笔记(3)

一、文本格式标签 效果标签&#xff08;旧版&#xff09;标签&#xff08;语义化&#xff0c;强调&#xff09;加粗<b><strong>倾斜<i><em>下划线<u><ins>删除线<s><del> 前面的标签 b 、 i 、 u 、 s 就仅仅是实现加粗、倾…

Postgresql源码(141)JIT系列分析汇总

JIT的东西比较零散&#xff0c;本篇对之前的一些列分析做个汇总、整理。 涉及&#xff1a; 《Postgresql源码&#xff08;113&#xff09;表达式JIT计算简单分析》 《Postgresql源码&#xff08;127&#xff09;投影ExecProject的表达式执行分析》 《Postgresql源码&#xff08…

Maven多环境打包方法配置

简单记录一下SpringBoot多环境打包配置方法&#xff0c;分部署环境和是否包含lib依赖包两个维度 目录 一、需求说明二、目录结构三、配置方案四、验证示例 一、需求说明 基于Spring Boot框架的项目分开发&#xff0c;测试&#xff0c;生产等编译部署环境&#xff08;每一个环境…

SDL2基本使用

前言 在这里记录SDL的环境基本搭建和使用&#xff0c;方便回忆。使用该图形库也是为了方便在没有单片机和显示模块的使用&#xff0c;也能对简单验证些关于图形构建或界面管理的猜想和测试&#xff0c;所以下述不会探讨过于深入的东西。当然&#xff0c;也可以通过SDL官网查看介…

【Linux系统编程】—— 从零开始实现一个简单的自定义Shell

文章目录 什么是自主shell命令行解释器&#xff1f;实现shell的基础认识全局变量的配置初始化环境变量实现内置命令&#xff08;如 cd 和 echo&#xff09;cd命令&#xff1a;echo命令&#xff1a; 构建命令行提示符获取并解析用户输入的命令执行内置命令与外部命令Shell的主循…

认识BOM

BOM 弹出层 可视窗口尺寸 屏幕宽高 浏览器内核和其操作系统的版本 剪贴板 是否允许使用cookie 语言 是否在线

[c语言日寄]结构体的使用及其拓展

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

Linux系统的第一个进程是什么?

Linux进程的生命周期从创建开始&#xff0c;直至终止&#xff0c;贯穿了一个进程的整个存在过程。我们可以通过系统调用fork()或vfork()来创建一个新的子进程&#xff0c;这标志着一个新进程的诞生。 实际上&#xff0c;Linux系统中的所有进程都是由其父进程创建的。 既然所有…

5. 马科维茨资产组合模型+AI金融智能体(qwen-max)识别政策意图方案(理论+Python实战)

目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…

PostMan最新版本及离线安装指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;PostMan是一款流行的API测试工具&#xff0c;它提供了一个直观的用户界面&#xff0c;方便Web开发者和测试人员进行接口测试。本文将指导你如何安装最新版的PostMan&#xff0c;包括在线安装和离线安装两种方法。…

记录一次k8s起不来的排查过程

我在k8s集群&#xff0c;重启了一个node宿主机&#xff0c;竟然发现kubelet起不来了&#xff01;报错如下 这个报错很模糊&#xff0c;怎么排查呢。这样&#xff0c;开两个界面&#xff0c;一个重启kubelet&#xff0c;一个看系统日志(/var/log/message:centos&#xff0c;/va…

grafana + Prometheus + node_exporter搭建监控大屏

本文介绍生产系统监控大屏的搭建&#xff0c;比较实用也是实际应用比较多的方式&#xff0c;希望能够帮助大家对监控系统有一定的认识。 0、规划 grafana主要是展示和报警&#xff0c;Prometheus用于保存监控数据&#xff0c;node_exporter用于实时采集各个应用服务器的事实状…

2024年博客之星主题创作|从零到一:我的技术成长与创作之路

2024年博客之星主题创作&#xff5c;从零到一&#xff1a;我的技术成长与创作之路 个人简介个人主页个人成就热门专栏 历程回顾初来CSDN&#xff1a;怀揣憧憬&#xff0c;开启创作之旅成长之路&#xff1a;从平凡到榜一的蜕变持续分享&#xff1a;打卡基地与成长复盘四年历程&a…