【iOS】简单的网络请求

news/2024/7/20 23:08:37 标签: ios, objective-c, 单例模式

应iOS小组要求,仿写知乎日报需要实现网络请求并解析JSON格式数据,这篇文章仅对基本的网络请求iOS中的JSON解析作以记录,还涉及到RunLoop的一点小插曲,具体请求过程和原理以后会详细学习!🙏

    • 基本网络流程
    • 简单的网络请求示例
    • JSON解析
    • 网络请求图示
    • JSON格式也可以通过第三方库JSONModel直接在程序中解析,后续将加以学习🫡
    • 网络请求其实可通过第三方库AFNetworking来进行,为我们简化了许多流程,后续将加以学习🤟🏻
    • 有关RunLoop的小插曲


基本网络流程

  • NSURL(Uniform Resource Locator)

URL可直接理解为请求网址,如:https://v0.yiketianqi.com/api?unescape=1&version=v9&appid=72961936&appsecret=m78Z0m2T&city=北京&unescape=1

其格式为:[协议类型]://[服务器器地址]:[端⼝口号]/[资源层级UNIX⽂文件路路径][⽂文件名]?[查询]#[⽚片段ID]

方法URLWithString:将要请求的地址字符串包装成NSURL对象:
请添加图片描述

  • NSURLRequest

NSURLRequest对象就代表一个请求
请添加图片描述
会将NSURL对象以及各种参数设置封装起来,无需设置其他参数时方法+ (instancetype)requestWithURL:(NSURL *)URL;即可

  • NSURLSession

一个session可创建多个请求request,并负责接收、发送和处理请求
整个程序中也可以有多个session

创建session方法(单例sharedSession):
请添加图片描述

session会将request封装成Task:
请添加图片描述
来处理数据

可以看到,如果请求逻辑没那么复杂,也可直接用第二个方法将NSURL封装成session

    • NSURLSessionTask
      请添加图片描述
      用Task类的resume方法来开启请求

简单的网络请求示例

用一个方法dataLoader封装一下,最后在Controller中调用次此方法

- (void)dataLoader {
    self.dict = [[NSDictionary alloc] init];
            
    NSString* urlString = @"https://v0.yiketianqi.com/api?unescape=1&version=v9&appid=72961936&appsecret=m78Z0m2T&city=北京&unescape=1";

    //处理字符
    //urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]];

    //创建url
    NSURL* url = [NSURL URLWithString: urlString];
    
    //NSURLRequest* request = [NSURLRequest requestWithURL: url];
    
    //创建session
    NSURLSession* session = [NSURLSession sharedSession];
    
    //创建task
    NSURLSessionTask* task = [session dataTaskWithURL: url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            //解析数据
            //self.dict = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &error];
            NSLog(@"%@", data);
        } else {
            NSLog(@"请求出现错误:%@", error);
        }
    }];

    //任务启动,开始请求
    [task resume];
}

JSON解析

请求下来的数据是NSData,二进制流
请添加图片描述

下面用一个类NSJSONSerialization将该数据转换成对象,用字典接收并打印出来:

self.dict = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &error];
NSLog(@"%@", self.dict);

请添加图片描述

解析成对象我们仍旧看不懂,这里编码格式是Unicode转义序列这就需要JSON解析(Unicode转中文, … , …),网上有许多JSON解析在线工具

在这里插入图片描述

网络请求图示

下面用一张图展示网络请求流程:

在这里插入图片描述


JSON格式也可以通过第三方库JSONModel直接在程序中解析,后续将加以学习🫡

网络请求其实可通过第三方库AFNetworking来进行,为我们简化了许多流程,后续将加以学习🤟🏻

有关RunLoop的小插曲

编者一开始其实是在main函数里调用并执行请求的,最后发现command Line Tool并没有显示打印内容,咨询了zxb10学长发现原来是RunLoop的问题

RunLoop 是一个事件循环,负责处理各种事件,包括网络请求的回调。在进行异步网络请求时,通常会使用回调函数或代理方法来处理请求的响应。这些回调函数或代理方法需要在 Run Loop 中执行,才能正确地接收和处理网络请求的响应

  • main函数中,默认情况下并没有启动RunLoop,因此当网络请求的回调发生时,由于Runloop没有运行,无法处理这些事件,包括打印输出
  • 而在iOS项目中,主线程的RunLoop默认会启动,并且在主RunLoop运行期间,ta会一直处于运行状态,直到应用程序退出。这意味着主线程的RunLoop会不断地处理事件,包括网络请求的回调和其他消息

为了解决这个问题,可以在main函数中创建一个自定义的RunLoop,并在其中执行网络请求。这样,网络请求的回调就能够在正确的上下文中被执行,从而使打印输出能够正常显示

- (void)dataLoader {

    // 创建一个自定义 Runloop,并运行在主线程上
    NSRunLoop *runloop = [NSRunLoop mainRunLoop];
    
    self.dict = [[NSDictionary alloc] init];
            
    NSString* urlString = @"https://v0.yiketianqi.com/api?unescape=1&version=v9&appid=72961936&appsecret=m78Z0m2T&city=北京&unescape=1";
    
    //创建url
    NSURL* url = [NSURL URLWithString: urlString];
    
    //创建session
    NSURLSession* session = [NSURLSession sharedSession];
    
    //创建task
    NSURLSessionTask* task = [session dataTaskWithURL: url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            //解析数据
            self.dict = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &error];
            NSLog(@"%@", self.dict);
        } else {
            NSLog(@"请求出现错误:%@", error);
        }
         // 停止自定义 Runloop
         CFRunLoopStop([runloop getCFRunLoop]);
    }];

    //任务启动,开始请求
    [task resume];

    // 运行自定义 Runloop
    [runloop run];
}

http://www.niftyadmin.cn/n/5111357.html

相关文章

Spring中自定义类型转换器

目录 一、什么是类型转换器 二、自定义类型转化器 2.1 实现Converter接口 2.2 在Spring中注册 三、自定义类型转换器中的细节 3.1 解决代码的耦合 3.2 注册标签id值必须唯一 ​3.3 Spring提供的日期转换器 一、什么是类型转换器 在Spring中类型转换器就是将配置文件中的字符串…

[AUTOSAR][诊断管理][$11] 复位服务

文章目录 一、简介(1) 应用场景(2) 请求格式(3) 重启类型 二、示例代码(1) 11_ecu_reset.c 一、简介 ECU复位服务就是可以此诊断指令来命令ECU执行自复位,复位有多种形式,依据子功能参数来区分&#xff08…

【题解 树形dp 拆位】 树上异或

「KDOI-06-S」树上异或 题目描述 给定一棵包含 n n n 个节点的树,第 i i i 个点有一个点权 x i x_i xi​。 对于树上的 n − 1 n-1 n−1 条边,每条边选择删除或不删除,有 2 n − 1 2^{n-1} 2n−1 种选择是否删除每条边的方案。 对于…

集成学习方法之随机森林-入门

1、 什么是集成学习方法 集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。 2、 什么是随机森林 在机器学习中&…

Python--循环中的两大关键词 break 与 continue

在Python循环中,经常会遇到两个常见的关键词:break 与 continue break:代表终止整个循环结构 continue:代表中止当前本次循环,继续下一次循环 break: 英 /breɪk/ v. 打破,打碎&#xff0c…

论坛介绍|COSCon'23 开源百宝箱(T)

众多开源爱好者翘首期盼的开源盛会:第八届中国开源年会(COSCon23)将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是:“开源:川流不息、山海相映”!各位新老朋友们,欢迎到成都&a…

NRK3301语音芯片在智能窗帘上的应用

窗帘是人们日常生活中所经常使用的家居产品,传统的窗帘大多都需要手动拉动窗帘使用;存在着拉拽费劲,挂钩容易掉落等问题。随着数字化转型的升级,推进了窗帘市场的高质量发展。智能窗帘也“适时出现”出现了,一款带有语…

【已解决】Unity 使用NPOI 写word文档报错:System.TypeLoadException:……0.86.0.518

报错显示 System.TypeLoadException: Could not resolve type with token 01000080 from typeref (expected class ICSharpCode.SharpZipLib.Zip.UseZip64 in assembly ICSharpCode.SharpZipLib, Version0.86.0.518, Cultureneutral, PublicKeyToken1b03e6acf1164f73) at NPOI.…