OC-AFNetworking

文章目录

  • AFNetworking
    • 简介
    • 问题
      • 🤔
      • 优化策略
    • 解决AFNetworking局限性
      • 使用单例进行网络请求的优势
      • 使用单例进行网络请求的风险
      • 最优使用
    • 使用
    • 参数讲解
    • POST请求

AFNetworking

简介

这篇文章旨在实现使用AFNetworking设置一个集中的单通道网络对象,该对象与MVC组建分离,可以在整个解耦架构应用程序中重复使用

资料来源:https://www.toptal.com/ios/afnetworking-tutorial-with-a-singleton-class?utm_source=chatgpt.com

虽然苹果抽象的许多iOS SDK在管理移动硬件的许多复杂性方面做的很好,但是在某些情况下为了保持SDK的灵活性,使用会很复杂。AFNetworking作为开源框架之一,简化了developer的日程任务。 他简化了RESTful API网络,并创建了具有成功、进度、和失败的模块化请求/响应模式。消除了对开发人员实施的委托方法和自定义请求/连接设置的需求,并且可以非常快速的包含在任何类中

问题

虽然AFN是一个功能强大、模块化的网络库,但是也会存在一些低效实施。如下

🤔

  • 分散的网络请求逻辑
    • 单个视图控制器包含多个几乎相同的请求,难以复用,后期维护成本高
    • 如果API发生变更,需要逐个排查所有使用的地方,容易遗漏
  • 共享状态混乱
    • 一些通用参数可能分散在不同的控制器中,容易出现不一致或者同步问题
  • 职责分离不清
    • 视图控制器承担了数据获取的职责,导致控制器代码臃肿
  • 拓展性不足
    • 如果API发生版本化或者新增参数,修改成本大

优化策略

  • 集中化网络层设计
    • 创建独立的NetworkManager或APIClient集中管理所有请求
    • 将通用的请求头、参数注入逻辑同意处理
  • 抽象请求方法
  • 引入模型层
    • 使用YY_Model等库,将API响应解析为强类型模型对象
    • 控制器只关心模型,不关心JSON结构
  • 支持版本或者参数设置
    • 在APIClient内部设计时预留一些字段

解决AFNetworking局限性

我们可以通过创建一个网络单例类来集中处理请求、响应以及其参数

苹果官方的原话:“A singleton object provides a global point of access to the resources of its class. Singletons are used in situations where this single point of control is desirable, such as with classes that offer some general service or resource. You obtain the global instance from a singleton class through a factory method. – Apple“

就是单例模式的介绍,想了解的可以看笔者前面有关单例模式的文章

使用单例进行网络请求的优势

  • 全局唯一,是静态初始化。保证了所有类访问的都是同一个实例,避免了因为不同实例不同步导致的奇怪bug
  • 同义API的调用和速率限制。单例可以集中管理请求队列和节流逻辑,防止因多个视图控制器并发请求导致速率限制
  • 集中化配置管理
  • 重复利用公共属性。通用的请求头、超时设置、解析策略都能复用。
  • 延迟加载、节省内存。单例在第一次使用前不加载,不占用内存
  • 解耦视图与网络层,即使视图控制器销毁,网络请求仍能继续,避免了因为界面消失导致网络请求中断的问题
  • 统一日志与错误处理
  • 跨项目复用

使用单例进行网络请求的风险

  • 可能承担过多职责,我们在使用单例时,每个单例应该只做一件事
  • 无法继承,单例不能被子类化,如果未来需要拓展,不够灵活。可以通过使用协议和依赖注入提供可替换的实现
  • 共享状态可能被意外修改
  • 长时间持有大量数据,不释放。可以定期清理缓存或者重置单例内部状态

最优使用

  • 单一职责原则
  • 线程安全,使用GCD或加锁
  • 轻量化存储,单例只存放必要的全局设置
  • 支持依赖注入
  • 提供重置能力,在必要时可以手动清空状态

使用

我们实现一个简单的GET请求来演示AFNetworking的效果

首先,我们先为项目导入需要的AFNetworking第三方库,这里的操作就略过了,我们直接进入正文

  • 创建单例类, 并实现GET方法
#import <Foundation/Foundation.h>
#import "AFNetworking.h"
NS_ASSUME_NONNULL_BEGIN@interface NetworkManager : NSObject
@property (nonatomic, strong)AFHTTPSessionManager* sessionManager;+ (instancetype)sharedManager;- (void)GET:(NSString* ) URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers progress:(nullable void (^)(NSProgress * _Nonnull))downloadProgress success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure;@endNS_ASSUME_NONNULL_END
//  Created by xiaoli pop on 2025/9/15.
//#import "NetworkManager.h"
static NetworkManager* sharedManager = nil;
@implementation NetworkManager
+ (instancetype)sharedManager {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{sharedManager = [[super allocWithZone:NULL] init];});return sharedManager;
}+ (instancetype)allocWithZone:(struct _NSZone *)zone {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{sharedManager = [super allocWithZone:zone];});return sharedManager;
}- (instancetype)init {if (self = [super init]) {self.sessionManager = [AFHTTPSessionManager manager];self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];self.sessionManager.requestSerializer.timeoutInterval = 15.0;self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];self.sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/plain", @"text/html", nil];}return self;
}- (void)GET:(NSString *)URLString parameters:(id)parameters headers:(NSDictionary<NSString *,NSString *> *)headers progress:(void (^)(NSProgress * _Nonnull))downloadProgress success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {[self.sessionManager GET:URLString parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {if (success) {success(task, responseObject);}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {if (failure) {failure(task, error);}}];
}@end
  • 使用
 NSString* str = @"安康";NSString* urlString  = [NSString stringWithFormat:@"https://api.weatherapi.com/v1/forecast.json?key=8f123b0cdc654b149aa92217252607&q=%@&days=3&lang=zh",str];urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];[[NetworkManager sharedManager] GET:urlString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {NSLog(@"%@", responseObject);} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"error");}];

我们对比一下原生的网络请求

- (void)creatURL {NSLog(@"!!!");NSString* str = @"安康";NSString* urlString  = [NSString stringWithFormat:@"https://api.weatherapi.com/v1/forecast.json?key=8f123b0cdc654b149aa92217252607&q=%@&days=3&lang=zh",str];urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];NSURL* url = [NSURL URLWithString:urlString];NSURLRequest* request = [NSURLRequest requestWithURL:url];NSURLSession* session = [NSURLSession sharedSession];NSURLSessionTask* task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if (!error && data) {NSError* jsonError;NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];if (!jsonError && [jsonDict isKindOfClass:[NSDictionary class]]) {// NSLog(@"%@", jsonDict);Model* model = [Model yy_modelWithDictionary:jsonDict];NSLog(@"%@", model.current[@"cloud"]);NSLog(@"%@", model);}} else {NSLog(@"ERROR: %@", error);}}];[task resume];
}

显而易见,当我们使用一个单例类来处理网络申请时,代码逻辑更清晰,后期维护更方便

参数讲解

  • URL
    • NSURL或者其字符串表示形式
    • 描述:网络资源的地址,制定了请求的目标位置
  • parameters
    • 类型:NSDictionary
    • 描述:字典,用于传递请求的参数,在GET请求中这些参数会附加到URL字符串中,以便于服务器根据这些参数返回对应数据
  • progress
    • 类型:通常是一个void(^)(NSprogress* downloadProgress)类型的块
    • 这个参数用于跟踪下载进度,他接收一个NSProgress对象,该对象包含了已下载的数据量、总数据量等信息。。可以在此实现更新进度条等操作,不需要可以传nil
  • headers
    • NSDictionary
    • 用于设置HTTP请求头部信息。
    • 每个请求头都是一对键值对,
  • success
    • 类型:void(^)NSURLSessionDataTask* task, id responseObject)类型的块
    • 请求成功后的回调块,通常接受两个参数,一个是包含响应数据的NSURLSessionDataTask对象,一个是响应数据,通常是一个NSDictionary或其他数据结构
  • failure
    • 失败后的回调块,第一个参数也是包含请求任务的NSURLSessionDataTask对象,第二个参数是一个NSError对象,包含了请求失败的信息

POST请求

在单例中:

- (void)POST:(NSString *)URLString parameters:(id)parameters headers:(NSDictionary<NSString *,NSString *> *)headers progress:(void (^)(NSProgress * _Nonnull))uploadProgress success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {[self.sessionManager POST:URLString parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {if (success) {success(task, responseObject);}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {if (failure) {failure(task, error);}}];
}

使用:

- (void)LoginWithUsrname:(NSString* )username withPassword:(NSString* )password {NSString* urlString = @"https://......./login";NSDictionary* parameters = @{@"username" : username , @"password" : password};[[NetworkManager sharedManager] POST:urlString parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"%@", responseObject);} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"%@", error);}];
}

APIURL是接口的基本路径,而parameters是传给接口的查询参数或请求体,AFNetworking会自动把parameters序列化并拼接到URL或者body,前提是必须得有一个基础URL来承接这些参数

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

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

相关文章

【数据结构】跳表

目录 1.什么是跳表-skiplist 2.skiplist的效率如何保证&#xff1f; 3.skiplist的实现 3.1节点和成员设计 3.2查找实现 3.3前置节点查找 3.4插入实现 3.5删除实现 3.6随机层数 3.7完整代码 4.skiplist跟平衡搜索树和哈希表的对比 1.什么是跳表-skiplist skiplist是由…

html实现右上角有个图标,鼠标移动到该位置出现手型,点击会弹出登录窗口。

写了一段html代码实现的效果&#xff1a;实现右上角有个图标&#xff0c;鼠标移动到该位置出现手型&#xff0c;点击会弹出登录窗口。功能实现前端&#xff0c;没有实现后端。<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF…

STM32G4 电流环闭环(二) 霍尔有感运行

目录一、STM32G4 电流环闭环(二) 霍尔有感运行2. 霍尔有感运行附学习参考网址欢迎大家有问题评论交流 (* ^ ω ^)一、STM32G4 电流环闭环(二) 霍尔有感运行 2. 霍尔有感运行 文章使用的BLDC在定子侧以互差120电角度的位置安装三个霍尔元件Ha&#xff0c;Hb&#xff0c;Hc。当…

展示框选择

好的&#xff0c;非常感谢您提供更详细的项目情况。这是一个非常典型的父子组件通信场景。 根据您的新需求&#xff0c;我将对代码进行重构&#xff1a; FaultSelect.vue (子组件): 这个组件现在将变得更加“纯粹”。它只负责自身的下拉框逻辑&#xff0c;不关心外部按钮&#…

第5课:上下文管理与状态持久化

第5课:上下文管理与状态持久化 课程目标 掌握上下文存储和检索策略 学习会话状态管理 了解数据持久化方案 实践实现上下文管理系统 课程内容 5.1 上下文管理基础 什么是上下文管理? 上下文管理是Agent系统中维护和利用历史信息的能力,包括: 对话历史:用户与Agent的交互…

计算机毕业设计 基于大数据技术的医疗数据分析与研究 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python、大数据、人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&…

K8S集群管理(2)

目录 1.什么是Pod的根容器&#xff1f; 2.解释Pod的生命周期。 3.Init类型容器有什么特点&#xff0c;主要用途&#xff1f; 4.Sidecar类型容器和Init容器的区别在哪&#xff1f; 5.什么是静态Pod&#xff1f; 6.说明K8s控制器的作用&#xff1f; 7.什么是ReplicaSet&#xff0…

视频全模态referring分割:Ref-AVS: Refer and Segment Objects in Audio-Visual Scenes

一、TL&#xff1b;DR 为什么要做&#xff1a;传统的referring分割无法使用音频模态&#xff0c;本文提出Reference audio-visual Segmentation本文怎么做&#xff1a;构建首个 Ref-AVS 基准数据集通过充分利用多模态提示&#xff0c;将音频信息通过和文本融合作为载体&#x…

A股大盘数据-20250916分析

&#x1f4ca; 一、大盘数据深度分析1.1 &#x1f9ee; 市场活跃度与资金流向总成交额&#xff1a;沪深京合计约 2.37万亿元&#xff0c;市场交投活跃&#xff0c;深市成交&#xff08;13516.4亿&#xff09;明显高于沪市&#xff08;9897.9亿&#xff09;&#xff0c;显示中小…

[计算机毕业设计]基于深度学习的噪声过滤音频优化系统研究

前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科同学来说是充满挑战。为帮助大家顺利通过和节省时间与精力投…

贪心算法应用:NFV功能部署问题详解

Java中的贪心算法应用&#xff1a;NFV功能部署问题详解 1. NFV功能部署问题概述 网络功能虚拟化(NFV, Network Function Virtualization)是一种将传统网络设备功能从专用硬件转移到虚拟化软件的技术。在NFV功能部署问题中&#xff0c;我们需要将各种虚拟网络功能(VNFs)部署到有…

SeriLog测试

安装Serilog.Sinks.Seq(5.2.3.0)&#xff0c;Serilog.Sinks.File(7.0.0) 下载Seq安装包并安装&#xff08;https://datalust.co/download&#xff09; 代码如下&#xff1a; private Logger _logger;private void button1_Click(object sender, EventArgs e){_logger new Lo…

HarmonyOS 5.0应用开发——V2装饰器@param的使用

【高心星出品】 文章目录V2装饰器param的使用概念使用方法案例V2装饰器param的使用 概念 在鸿蒙ArkTS开发中&#xff0c;Param装饰器是组件间状态管理的重要工具&#xff0c;主要用于父子组件间的单向数据传递&#xff0c;这一点与V1中的prop类似。 Param装饰的变量支持本地…

SLAM | 无人机视觉/激光雷达集群SLAM技术进展综述

主要内容如下: 无人机集群SLAM技术概述:介绍无人机集群SLAM的基本概念、重要性及面临的挑战,使用表格对比不同传感器配置的特点。 多传感器融合与协同SLAM架构:分析集中式、分布式和混合式协同架构的特点,使用表格对比不同架构的优缺点。 视觉协同SLAM的技术进展:总结直接…

信息化系统运维文档资料,运维服务方案,运维巡检方案

1、系统服务内容​1.1 服务目标​1.2 信息资产统计服务​1.3 网络与安全系统运维服务​1.4 主机与存储系统运维服务​1.5 数据库系统运维服务​1.6 中间件运维服务​2、服务管理制度规范​2.1 服务时间管理​2.2 运维人员行为规范​2.3 现场服务支持规范​2.4 问题记录与归档规…

JavaScript——document对象

DOM 是 document object model&#xff08;文档对象模型&#xff09;的缩写。它是一种与平台、语言无关的接口&#xff0c;允许程序动态地访问或更新 HTML、XML 文档的内容、结构和样式&#xff0c;且提供了一系列的函数和对象来实现增、删、改、查操作。DOM 对象的一个特点是&…

UART,IIC,SPI总线(通信协议)

嵌 入 式 软 件 笔 试 题要求&#xff1a;闭卷考试&#xff08;不能翻书、不能开电脑&#xff09;&#xff1b;作答时间50分钟&#xff1b;共10道题目。volatile的作用有哪些volatile&#xff1a; 防止编译器对代码进行优化&#xff0c;直接从内存中取最新的值 应用场景&#x…

通信模组性能调优

通信模组性能调优 1 背景 2 高通平台软硬加速 2.1 NSS 2.2 SFE 2.3 PPE 3 CPU 负载均衡设置 3.1 启用内核 RPS&RFS 功能 3.2 网卡队列修改建议 3.3 调整负载前后的 CPU 使用对比 3.4 网卡中断均衡 3.4.1 netdev_max_backlog 3.4.2 中断绑核 3.5 CPU性能模式 3.6 热管理 3.7…

消息队列kafka的事务特性

kafka的java客户端producer也支持事务消息吗&#xff1f;具体是啥事务呢&#xff1f; 是的&#xff0c;Kafka的Java客户端Producer确实支持事务消息。让我详细解释Kafka事务的概念和使用方法。 Kafka事务的主要特点&#xff1a; Producer Transactions&#xff1a;确保多个消息…

用Python实现自动化的Web测试(Selenium)

Python作为数据科学和自动化领域的主流语言&#xff0c;在网络爬虫开发中占据着重要地位。本文将全面介绍Python爬虫的技术栈、实现方法和最佳实践。爬虫技术概述网络爬虫&#xff08;Web Crawler&#xff09;是一种按照特定规则自动抓取互联网信息的程序。它可以自动化地浏览网…