• 【iOS】使用单例封装通过AFNetworking实现的网络请求



    前言

    先前在天气预报中笔者用到了Foundation框架中原生的网络请求NSURLSession,我们先来看一下我们通过NSURLSession请求网络数据的示例:

        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        request.HTTPMethod = @"GET";
        [request setValue:@"application/json" forHTTPHeaderField:@"Conten-Type"];
        
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if(error){
                NSLog(@"error = %@",error);
            }else{
                NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
                NSLog(@"dic = %@",dic);
            }
        }];
        [task resume];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接下来我们再看一下通过AFNetworking如何进行网络请求:

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        [manager GET:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"responseObject = %@",responseObject);
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            if (error) {
                NSLog(@"error = %@",error);
            }
        }];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这样一对比,很显然通过AFNetworking实现网络请求需要的代码量更少

    接下来笔者会通过示例具体讲解使用单例封装通过AFNetworking实现的网络请求

    单例封装网络请求

    在介绍单例封装网络请求的用法前,我们先来讲解一下我们为什么要使用单例来封装网络请求:

    在先前的天气预报中,因为有许多个页面,每个页面中都需要从网络中请求数据,因此笔者就创建多个对象来请求不同的网络数据,但是这无疑浪费了内存,如果有一个单例专门负责进行网络请求,就不会出现这样的问题,

    同时将网络请求逻辑封装到一个单例类中,这个类负责创建、管理和发送网络请求。这样,你可以将网络请求的相关代码集中在一个地方,以提高代码的可维护性和可读性。

    接下来笔者将通过示例讲解这方面的知识:

    1. 首先创建一个继承于NSObject的单例类,笔者这里以Manager对单例类进行命名,然后声明并实现单例类的初始化方法

    .h文件:
    在这里插入图片描述

    .m文件:

    //创建一个单例
    static Manager *managerSington = nil;
    
    @implementation Manager
    
    + (instancetype)shareManager {
        if (!managerSington) {
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                managerSington = [[Manager alloc] init];
            });
        }
        return managerSington;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里创建单例笔者使用了GCD,GCD在此的作用是确保代码块只被执行一次。这是线程安全的,即使在多线程环境下也不会出现问题。

    static dispatch_once_t onceToken;:这是用于确保代码块只执行一次的GCD的dispatch_once_t变量。

    dispatch_once(&onceToken, ^{ ... }):这是GCD的dispatch_once函数,它接受一个 dispatch_once_t 变量和一个代码块作为参数。它确保代码块中的代码只会在第一次调用时执行,以后的调用会被忽略。

    2.实现完单例的创建方法后我们即可通过AFNetworking中的GET方法进行网络请求

    - (void)NetWorkGetWithData:(id)TestModelBolck andError:(id)errorBlock {
    
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        
        NSString *url = @"https://news-at.zhihu.com/api/4/version/ios/2.3.0";
        
        [manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
            TestModel2 *testModel = [[TestModel2 alloc] initWithDictionary:responseObject error:nil];
            
            mainModelBolck(testModel);
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
            NSLog(@"Error: %@", error);
            
        }];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    我们接下来分析一下GET方法的源码对其进行解析:

    - (NSURLSessionDataTask *)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
    {
        
        NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
                                                            URLString:URLString
                                                           parameters:parameters
                                                              headers:headers
                                                       uploadProgress:nil
                                                     downloadProgress:downloadProgress
                                                              success:success
                                                              failure:failure];
        
        [dataTask resume];
        
        return dataTask;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    笔者在这里解释一下各个参数的含义

    URLString(NSString类型):表示要发送GET请求的URL字符串,即请求的目标地址。
    parameters(可选的id类型):包含GET请求的参数,这些参数会附加到URL字符串中,以便服务器可以根据这些参数返回相应的数据。它通常是一个NSDictionary或其他数据结构,其中包含键值对,表示请求参数。
    headers(可选的NSDictionary类型):包含HTTP请求头的字典。HTTP请求头通常包含与请求相关的信息,例如授权令牌、用户代理、接受的数据类型等。这里的参数允许你自定义请求头。
    downloadProgress(可选的NSProgress类型块):一个块对象,用于跟踪下载进度。这个块会在下载数据时被调用,可以用来更新UI或记录下载进度等。
    success(可选的块):一个成功回调块,当请求成功完成时会被调用。这个块通常接受两个参数,第一个参数是包含响应数据的NSURLSessionDataTask对象,第二个参数是响应数据,通常是一个NSDictionary或其他数据结构。
    failure(可选的块):一个失败回调块,当请求失败时会被调用。这个块通常接受两个参数,第一个参数是包含请求任务信息的NSURLSessionDataTask对象,第二个参数是一个NSError对象,包含了关于请求失败的信息。
    在这个方法内部,首先通过调用dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:方法创建一个NSURLSessionDataTask对象,然后使用resume方法开始执行这个任务(发送GET请求),最后返回该任务对象,以便调用者可以对任务进行进一步操作或取消。

    关于AFNetworking的源码以后还会深度学习,在GET方法中需要注意的是当我们请求成功后返回的id _Nullable responseObject,这个参数是响应数据,通常是一个NSDictionary或其他数据结构。我们通过将responseObject赋值给我们的JSONModel对象即可得到我们从网络中请求到的数据

    当我们成功请求到数据并将其放入我们的对象后,我们通过Block传值将其对象传递给到我们的其他文件中

    typedef void (^TestModelBlock) (TestModel2 *model);
    typedef void (^TestModelBlockElse) (TestModel3 *model);
    
    • 1
    • 2

    然后在实现文件中进行代码块的传递:

        [manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
            TestModel2 *testModel = [[TestModel2 alloc] initWithDictionary:responseObject error:nil];
            
            mainModelBolck(testModel);
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
            NSLog(@"Error: %@", error);
            
        }];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.在Controller文件中创建单例并执行网络请求的方法

        [[Manager shareManager] NetWorkGetWithData:^(TestModel2 *TestModelBolck) {
            NSLog(@"%@",TestModelBolck);
            NSLog(@"请求成功");
        } andError:^(NSError * _Nullable error) {
            NSLog(@"失败");
        }];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    综合以上这三步我们就成功使用单例封装通过AFNetworking实现的网络请求

  • 相关阅读:
    Windows 10 python pcl 安装与测试
    Thinkphp漏洞远程代码执行漏洞事件分析报告
    使用xss来打cookie
    46道面试题带你了解高级Java面试
    python flask 入门-helloworld
    小节9:Python之numpy
    【教3妹学java】11.强引用,弱引用,软引用和虚引用的区别是什么?
    MySQL进阶实战10,MySQL全文索引
    【算法与数据结构】700、LeetCode二叉搜索树中的搜索
    明白这3个规则,行走职场简直没有难度
  • 原文地址:https://blog.csdn.net/weixin_72437555/article/details/133904672