在使用 RESideMenu 显示视图控制器之前,使用 AFNetworking 在 didFinishLaunching 中尽快检查可达性

Posted

技术标签:

【中文标题】在使用 RESideMenu 显示视图控制器之前,使用 AFNetworking 在 didFinishLaunching 中尽快检查可达性【英文标题】:Check reachability asap in didFinishLaunching using AFNetworking before a view controller visible with RESideMenu 【发布时间】:2014-12-26 10:10:09 【问题描述】:

我在我的应用程序中使用AFNetworking,我正在通过他们的内置类检查互联网连接。这是这个的代码,

- (void) startInternetConnectivityMonitoring

    [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
    
        switch (status) 
            case AFNetworkReachabilityStatusUnknown:
            case AFNetworkReachabilityStatusReachableViaWWAN:
            case AFNetworkReachabilityStatusReachableViaWiFi:
                break;
            case AFNetworkReachabilityStatusNotReachable:
                break;
            default:
                break;
        

        NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));

    ];

    [[AFNetworkReachabilityManager sharedManager] startMonitoring];

我可以通过这个函数来检查它,

- (BOOL) connected 
    return [AFNetworkReachabilityManager sharedManager].reachable;

我还在我的应用程序中使用RESideMenu 来设置侧边菜单,这是我的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    [self startInternetConnectivityMonitoring];

    RootViewController *rootView = [[RootViewController alloc] init];
    [rootView awakeFromNib];
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = rootView;
    [self.window makeKeyAndVisible];
    return YES;

除了 FirstViewController 之外,所有其他视图控制器都可以正常工作。在 FirstViewController 中,我正在调用网络请求,在此之前,我会检查互联网连接。这就是问题所在。每次,它都会向我显示 No internet 的 FirstViewController。因为,当它调用网络请求时,AFNetworking 不会更新互联网的状态。更新可能需要几秒钟的摩擦,但更新速度不会那么快。因为,我知道这个问题,我不想应用补丁来解决这个问题。我尝试了不同的方法来解决这个问题。用过,

sleep(2); 在从didFinishLaunchingWithOptions... 返回 YES 之前

dispatch_synq - 冻结应用

dispatch_asynq - 不起作用

.. and many other hacky ways - 还没有帮助。

【问题讨论】:

【参考方案1】:

不幸的是,确定连接需要一段时间,因此可能不会尽快发生。但是,您也可以注册以接收可达性通知,而不是假设您有互联网连接。在 AppDelegate didFinishLaunchingWithOptions:launchOptions 开始你的监控:

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

在您的 FirstViewController viewDidLoad 或 viewWillAppear 中,注册以接收通知:

 [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(reachabilityChanged:)
                                              name:AFNetworkingReachabilityDidChangeNotification
                                            object:nil];

然后在FirstViewController中添加一个方法来处理通知:

- (void)reachabilityChanged:(NSNotification *)notification
       
    if([[AFNetworkReachabilityManager sharedManager].isReachable)
    
        // Do web service stuff here
    
    else
    
        // Do non webservice stuff
    

如果您需要知道状态是什么,可以从通知的 userInfo 字典中获取:

- (void)reachabilityChanged:(NSNotification *)notification

    NSLog(@"Rechability Changed: %@", notification.userInfo);
    BOOL reachable;
    NSInteger status = [[notification.userInfo objectForKey:@"AFNetworkReachabilityNotificationStatusItem"] integerValue];
    switch(status)
    
        case AFNetworkReachabilityStatusNotReachable:
            NSLog(@"No Internet Connection");
            reachable = NO;
            break;
        case AFNetworkReachabilityStatusReachableViaWiFi:
            NSLog(@"WIFI");
            reachable = YES;
            break;
        case AFNetworkReachabilityStatusReachableViaWWAN:
            NSLog(@"3G");
            reachable = YES;
            break;
        default:
            NSLog(@"Unkown network status");
            reachable = NO;
        break;
    
    // do stuff with reachable

一旦 AFReachabilityManager 确定网络状态,通知就会发出,并且总是至少发出一次。

如果您只需要获取一次状态,您可以在处理通知的方法中从通知中心取消注册 FirstViewController - 从所有通知中:

[[NSNotificationCenter defaultCenter] removeObserver:self];

或针对特定通知:

[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNetworkingReachabilityDidChangeNotification object:nil];

【讨论】:

【参考方案2】:

我为此找到了一个简单的补丁,是的,它应该像一个魅力一样工作,而我找不到这个问题的合理解决方案。

    我在AppDelegate.hBOOL isCalledOnce; 中取了一个BOOL

    在 (AppDelegate.m) 中添加了如下两个方法
- (void) setAppRequestCallOnce 
   isCalledOnce = YES;

 - (BOOL) checkAppRequestCalledOnce 
    return isCalledOnce;
 

    在可达性检查中,我做了这样的条件,
- (BOOL) connected 
    if(![self checkAppRequestCalledOnce]) 
        [self setAppRequestCallOnce];
        return YES;
    
    return [AFNetworkReachabilityManager sharedManager].reachable;


结论:

来自FirstViewController,当我检查可达性时,例如,

if(![delegateObj connected]) 
    //show no internet message

这将首先调用checkAppRequestCalledOnce 方法,该方法返回一个isCalledOnce,如果它是NO,那么我将其设置为YES 并返回YES(这里我们不确定可达性)。从现在开始,当我再次检查可达性时,它不会检查上述条件,而是返回实际的可达性状态。

我为什么要使用,因为即使一开始没有可用的互联网,AFNetworking 也会给我们一个错误,尽管我们可以显示它,即使我们没有实际的可达性状态。

如果您发现任何更优雅的方式,请发布或评论。

【讨论】:

【参考方案3】:

我遇到了类似的问题。 AFNetworking 似乎需要一点时间才能启动。如果你想在应用程序中检查互联网连接:didFinishLaunchingWithOptions:使用:

Reachability *reach = [Reachability reachabilityForInternetConnection];

if (reach.currentReachabilityStatus != NotReachable) 
    //NSLog(@"internet available");

或在 AFNetworking 上设置块并等待它被调用:

[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) 
    if (status < ReachableViaWiFi) 
        // no connection
     else 
        // connected
    
];

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

【讨论】:

【参考方案4】:

我也遇到过同样的问题。之后,我尝试在调用 web-service 时延迟 0.3 秒,它解决了我的问题。

您可以尝试在FirstViewController 中调用网络服务之前延迟一些时间。因为AFNetworking 需要时间来监控互联网状态,并且您的控制器在AFNetworking 获得互联网状态之前加载。所以每次你都会得到AFNetworkReachabilityStatusNotReachable

FirstViewController 调用 web-service 之前稍作延迟,它可能会解决您的问题。

【讨论】:

【参考方案5】:

如果您检查networkReachabilityStatus 中的AFNetworkReachabilityStatusUnknown,AFNetworking 会告诉您它尚未确定状态。因此,执行此操作的干净方法是仅在已知状态后使用reachable 状态。例如:

- (void)networkReachableWithCompletion:(CompletionBlock)_completion

    if (!_completion) return; //no point continuing

    if ([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus != AFNetworkReachabilityStatusUnknown) 
        _completion([NSNumber numberWithBool:[AFNetworkReachabilityManager sharedManager].reachable]);
     else 
        [self performSelector:@selector(networkReachableWithCompletion:) withObject:_completion afterDelay:0.3];
    

【讨论】:

以上是关于在使用 RESideMenu 显示视图控制器之前,使用 AFNetworking 在 didFinishLaunching 中尽快检查可达性的主要内容,如果未能解决你的问题,请参考以下文章

带有 Residemenu 的 UILocalNotification

使用 RESideMenu 移动到其他视图

显示时更新 RESideMenu 中的 tableview 数据

如何在加载视图控制器之前使用来自服务器/数据库的数据来显示视图控制器

在选项卡控制器视图之前显示登录屏幕

自定义 Segue 在显示目标视图控制器之前动画为黑色