iOS取消网络请求实现

对于怎样取消网络请求  之前有朋友也问我   当界面一出现的时候就要进行网络请求 然后切换界面时也要进行网络请求  这个时候要是用户两手指不停的点击不同的界面  那么每次点击都需要进行一次请求  如果请求不中断  那么服务器会不停的进行数据返回  甚至还会产生一些其他的问题  非常的不友好 那么怎么对网络请求进行中断  这也是我们今天要写的内容  

新建一个实体类  叫SuperNetworkManager  在.h中声明一个网络请求方法  .m中实现该方法 使得所有请求都调用同一个方法  只是传入的参数不同而已

.h中代码如下:

#import <Foundation/Foundation.h>

#import "NetworkAddress.h"

#import <AFNetworking.h>

#import "ResultDesc.h"

 

/**

 网络用到的的Block

 

 @param res 网络请求返回的结果

 */

typedef void(^ResultDescBlock)(ResultDesc *res); //回调

 

@interface SuperNetworkManager : NSObject

 

/**

 网络请求属性  该属性目的当网络还在进行中时 进行界面切换等操作 能够取消掉该请求

 */

@property (nonatomic, strong) NSURLSessionDataTask *task;

 

/**

 需要进行网络请求调用的方法

 @param parameters 传入的参数

 @param resBlock 网络请求返回的结果

 */

- (void )fetchDataWithparameters:(NSDictionary *)parameters ResultDesc:(ResultDescBlock)resBlock;

 

/**

 单例模式

 @return 网络请求实体类的对象

 */

+ (SuperNetworkManager *)shareManager;

 

/**

 取消网络请求

 */

- (void)networkCancle;

@end
 

 

.m中代码如下

#import "SuperNetworkManager.h"

 

@implementation SuperNetworkManager

 

+ (SuperNetworkManager *)shareManager

{

    static SuperNetworkManager *manager = nil;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        manager = [[SuperNetworkManager alloc] init];

    });

    return manager;

}

 

- (void)networkCancle

{

    [self.task cancel];

}

 

- (void)fetchDataWithparameters:(NSDictionary *)parameters ResultDesc:(ResultDescBlock)resBlock{

    

    ResultDesc *res = [[ResultDesc alloc]init];

    if (ConnectEnabled == ConnectNot){

        res.desc = @"当前网络不可用,请检查网络连接状态";

        resBlock(res);

        return ;

    }

    

    AFHTTPSessionManager *session = [AFHTTPSessionManager manager];

    session.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

    session.responseSerializer = [AFHTTPResponseSerializer serializer];

    [session.requestSerializer willChangeValueForKey:@"timeoutInterval"];

    session.requestSerializer.timeoutInterval = 10.f;

    [session.requestSerializer didChangeValueForKey:@"timeoutInterval"];

    self.task = [session POST:SERVERURL parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject){

        

        //对返回的值进行解析

        id responseObj  = [self parseJson:responseObject];

        if ([responseObj isKindOfClass:[NSDictionary class]]){

            responseObj = (NSDictionary *)responseObj;

        }

        //如果返回值为空  则网络异常  本来这个不用写的  因为当时测试有段时间公司早上9.30之前禁网发现登陆时返回值不存在  这也是特殊情况 偶然发现的  故此加上一个判断

        if (!responseObj){

            res.desc = @"网络异常";  //对异常描述进行手动标明异常情况

            resBlock(res);

            return ;

        }

        //给接收网络请求的数据进行赋值  该情况表示正常请求成功 但不表示一定能拿到需要的数据  可能服务器也会返回员工编号不能为空等desc说明  这里只是表示跟服务器进行了交互 服务器返回了数据

        ResultDesc *res = [[ResultDesc alloc]init];

        [res mj_setKeyValues:responseObj];

        resBlock(res);

        

    }failure:^(NSURLSessionDataTask *task, NSError *error){

        if (error.code == -1001){   //当返回的状态码为-1001时  表示请求超时 手动标明异常情况

            res.desc = @"请求超时";

        }else{

            res.desc = @"网络连接异常";  //其它失败情况 均手动标注为网络连接异常或服务器连接异常

        }

        resBlock(res);

    }];

 

}

 

 

/**

 对网络请求的数据进行解析

 @param responseObject 网络请求拿到的数据

 @return 解析后的数据

 */

- (id)parseJson:(id)responseObject{

    NSError *error = nil;

    id jsonObject;

    if ([responseObject isKindOfClass:[NSData class]]) {

        jsonObject = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];

    }

    

    return jsonObject;

}

 

代码举例说明使用情况和方法

/**

 界面即将出现

 */

- (void)viewWillAppear:(BOOL)animated{

    [super viewWillAppear:animated];

    

    NSDictionary *data_paramas = [NetworkAddress parametersWithDataParamsOjbect:@{} andMethod:@"app.test"];

    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];

    hud.opacity = 0.7;

    hud.mode = MBProgressHUDModeIndeterminate;

    hud.labelText = @"请求测试...";

    [hud show:YES];

    

    [[SuperNetworkManager shareManager] fetchDataWithparameters:data_paramas ResultDesc:^(ResultDesc *res) {

        [hud removeFromSuperview]; //移除网络请求提示框

        if (res.success) { //请求成功  再进行成功操作  try catch包裹防止异常情况

            @try {

                

                

            }@catch (NSException *exception) {

 

            }@finally{

 

            }

 

        }else{

            [MBProgressHUD showError:res.desc];//请求不成功的描述

        }

 

    }];

    

}

 

/**

 界面即将消失

 */

- (void)viewWillDisappear:(BOOL)animated{

    [super viewWillDisappear:animated];

    [[SuperNetworkManager shareManager]networkCancle];//取消网络请求

}

### 如何在 iOS 中使用 Moya 取消网络请求iOS 开发中,当需要取消由 Moya 库发起的网络请求时,可以通过管理 `Cancellable` 对象实现这一功能。Moya 的每次请求都会返回一个符合 `Cancellable` 协议的对象,调用其 `cancel()` 方法即可中断正在进行的请求。 以下是具体的代码示例以及解释: #### 实现取消单个网络请求 如果只需要取消某次特定的网络请求,可以在发送请求时保存该请求的 `Cancellable` 对象,并在其生命周期结束前手动调用 `cancel()` 方法。 ```swift import UIKit import Moya class ViewController: UIViewController { var cancellableToken: Cancellable? // 用于存储当前正在执行的请求 override func viewDidLoad() { super.viewDidLoad() // 发起网络请求并保留 cancellable 对象 self.cancellableToken = NetworkManager.shared.provider.request(.getUser(id: 123)) { result in switch result { case .success(let response): do { let json = try response.mapJSON() print("User Info: \(json)") } catch { print("解析错误: \(error)") } case .failure(let error): print("请求失败: \(error)") } // 清除 token 防止内存泄漏 self.cancellableToken = nil } // 示例:稍后取消请求 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { self.cancellableToken?.cancel() print("已取消请求") } } } ``` 此代码片段展示了如何通过保存 `cancellableToken` 并在适当时候调用 `.cancel()` 来终止未完成的请求[^3]。 --- #### 批量取消多个网络请求 对于批量取消操作,通常会在视图控制器销毁或切换场景时统一清理所有挂起的任务。这可以通过自定义扩展或者重写基类方法来实现。 以下是一个基于 BaseViewController 的实现方式,适用于多种退出场景(如 dismiss 或 pop)下的自动清除逻辑: ```objc #pragma mark - Override Methods - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 自动取消所有关联到本页面请求任务 [self cancelAllSessionDataTask]; } - (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion NS_AVAILABLE_IOS(5_0){ [self cancelAllSessionDataTask]; // 调用取消函数 [super dismissViewControllerAnimated:flag completion:completion]; } // 添加取消会话数据任务的方法 - (void)cancelAllSessionDataTask{ [[NetworkManager shared].provider.session getTasksWithCompletionHandler:^(NSArray<NSURLSessionTask *> * _Nonnull dataTasks, NSArray<NSURLSessionUploadTask *> * _Nonnull uploadTasks, NSArray<NSURLSessionDownloadTask *> * _Nonnull downloadTasks) { for (NSURLSessionTask *task in dataTasks) { [task cancel]; } }]; } ``` 上述 Objective-C 版本实现了在 viewController 生命周期变化期间触发请求清理的功能[^2]。 --- #### 设置唯一标识符以便精确控制 为了更灵活地管理和追踪各个独立请求的状态,在某些情况下还可以引入唯一的字符串作为每条请求的身份标记。例如,可以利用字典结构记录这些活动连接及其对应的 cancellation handler。 ```swift var activeRequests: [String: Cancellable] = [:] func fetchUserData(userId: Int, identifier: String) { guard !activeRequests.keys.contains(identifier) else { print("\(identifier) 已存在,跳过重复加载") return } let newRequest = NetworkManager.shared.provider.request(.getUser(id: userId)) { result in defer { self.activeRequests.removeValue(forKey: identifier) } // 移除已完成项 switch result { case .success(let response): do { let json = try response.mapJSON() print("成功获取用户信息 (\(userId)): \(json)") } catch { print("解析异常: \(error.localizedDescription)") } case .failure(let error): print("发生错误: \(error.errorDescription ?? "")") } } activeRequests[identifier] = newRequest } // 后续可通过 ID 查找并停止目标请求 func stopFetchingData(forIdentifier id: String) { if let pendingReq = activeRequests[id]?.cancel(), pendingReq != nil { print("已尝试取消请求 '\(id)'") } else { print("无法找到匹配的请求取消") } } ``` 这种方法允许开发者按需启动/暂停任意数量的不同查询过程,同时保持良好的资源利用率和用户体验一致性。 --- ### 总结 以上介绍了三种主要策略——单独撤销个别事务、集体清空全部待办事项列表以及借助键值映射机制精准定位具体实例来进行干预。实际项目里可根据需求选用最合适的方案组合应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值