【iOS】简单的网络请求

应iOS小组要求,仿写知乎日报需要实现网络请求并解析JSON格式数据,这篇文章仅对基本的网络请求iOS中的JSON解析 作以记录,还涉及到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中调用次此方法

objectivec 复制代码
- (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将该数据转换成对象,用字典接收并打印出来:

objectivec 复制代码
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,并在其中执行网络请求。这样,网络请求的回调就能够在正确的上下文中被执行,从而使打印输出能够正常显示

objectivec 复制代码
- (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];
}
相关推荐
sakiko_1 小时前
OC学习笔记-面试题
面试·objective-c
Anhty9 小时前
2026 实测 4 款 AI 变声器|QQ 聊天伪装声线,告别僵硬假声
人工智能·功能测试·ios·智能手机·安卓
2301_7779983410 小时前
C++ 单例模式详解:饿汉、懒汉,以及“对象”和“对象指针”到底有什么区别
开发语言·c++·单例模式
唔6611 小时前
flutter web iOS 在浏览器加载中文慢的问题
前端·flutter·ios
ZacJi18 小时前
我为 DeepSeek Harness 写了一个 dsh-apple-mode 插件
ios·deepseek·vibecoding
2501_915921431 天前
抓包鹰 Traceeagle 解除证书绑定,SSL Pinning 解除
网络·网络协议·网络安全·ios·adb·https·ssl
做萤石二次开发的哈哈1 天前
开发者如何调用 ERTC iOS API 完成 SDK 初始化配置?
macos·objective-c·cocoa
人月神话Lee1 天前
我做了个不要账号、不要定位权限的旅行 App,聊聊那些「不做」的决定
ios·ai编程·产品
2501_916007472 天前
Bundle ID 注册与管理 App ID 创建指南 命名规则 权限开关与删除注意事项
android·ios·小程序·https·uni-app·iphone·webview