iOS问题:使用Reachability检查网络后connectionDidFinishLoading未调用
解决Reachability检查后NSURLConnection代理方法不触发的问题
这个问题我之前也碰到过,大概率是Reachability回调线程和NSURLConnection依赖的RunLoop不匹配导致的,我给你拆解下核心原因和对应的解决办法:
核心原因分析
Reachability的状态变更回调block默认是在后台线程执行的,而旧版的NSURLConnection(你用的应该是代理模式)依赖创建它的线程的RunLoop才能触发代理方法(比如connectionDidFinishLoading:)。
如果在后台线程的block里直接创建NSURLConnection,block执行完后后台线程会立即退出,RunLoop也就停止了,自然无法触发代理回调;而直接在主线程调用单例时,主线程的RunLoop是一直运行的,所以代理方法能正常执行。
解决方案
方案1:切换到主线程执行网络请求(最简单可靠)
把调用DataManagement的网络请求代码放到主线程的dispatch队列里,利用主线程持续运行的RunLoop来保证代理方法触发:
// 你的Reachability监听代码 self.reachability = [Reachability reachabilityForInternetConnection]; [self.reachability setReachabilityStatusChangeBlock:^(Reachability *reachability) { NetworkStatus status = [reachability currentReachabilityStatus]; if (status != NotReachable) { // 切换到主线程执行网络请求 dispatch_async(dispatch_get_main_queue(), ^{ [[DataManagement sharedInstance] callYourWebServiceMethod]; }); } else { NSLog(@"当前无网络连接"); } }]; [self.reachability startNotifier];
方案2:为NSURLConnection指定代理队列(不推荐,适用于必须在后台执行的场景)
如果一定要在后台线程执行请求,可以手动为NSURLConnection指定代理队列为主线程队列,这样代理方法会在主线程触发,不受后台线程生命周期影响:
// 在DataManagement的网络请求方法里修改 - (void)callYourWebServiceMethod { NSURLRequest *request = [self createWebServiceRequest]; // 你的请求创建逻辑 NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; // 指定代理队列为主线程队列 [connection setDelegateQueue:[NSOperationQueue mainQueue]]; [connection start]; }
方案3:改用NSURLSession(推荐,长期解决方案)
NSURLConnection已经被苹果废弃,推荐使用NSURLSession,它的代理/ completionHandler不依赖线程RunLoop,不管在哪个线程调用都能正常触发回调:
// DataManagement里的网络请求方法改用NSURLSession - (void)callYourWebServiceMethod { NSURL *url = [NSURL URLWithString:@"你的接口地址"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (!error) { // 处理返回数据,若需更新UI记得切回主线程 dispatch_async(dispatch_get_main_queue(), ^{ // 解析数据/通知UI更新的逻辑 NSLog(@"请求完成,数据长度:%lu", (unsigned long)data.length); }); } else { NSLog(@"请求失败:%@", error.localizedDescription); } }]; [task resume]; }
额外检查点
- 确认你的
DataManagement单例实现是线程安全的,避免多次创建实例导致代理丢失:
+ (instancetype)sharedInstance { static DataManagement *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance; }
- 确认
DataManagement已经遵守NSURLConnectionDataDelegate(如果用旧API)或NSURLSessionDataDelegate(如果用新API)协议。
内容的提问来源于stack exchange,提问作者ΩlostA
相关产品推荐
相关产品推荐

