Достижимость вызывает сбой после отсутствия сетевой ситуации - как правильно использовать Достижимость асинхронно - PullRequest
7 голосов
/ 05 мая 2011

Я столкнулся с очень странным сбоем в работе моего приложения для iPhone.Казалось, что каждый раз, когда я показываю свое приложение другу, оно падает, но иначе никогда не будет.Будучи в целом озадаченным аспектом Закона Мерфи, я определил схему аварий - метро Нью-Йорка.Мое приложение постоянно падает после того, как я пользуюсь метро.Я проследил проблему до моего использования Reachability.Приложение вылетает в следующий раз после того, как оно используется в ситуации отсутствия сети (не включая режим полета).Я следую рекомендациям Apple и проверяю соединение с Reachability, прежде чем выполнять какие-либо другие сетевые операции, но я нашел противоречивую документацию о том, как его вызвать.

В настоящее время я что-то делаюкак это:

-(BOOL)reachable {
    Reachability *r = [Reachability reachabilityWithHostName:@"www.stackoverflow.com"];
    NetworkStatus internetStatus = [r currentReachabilityStatus];
    if(internetStatus == NotReachable) {
        return NO;
    }
    return YES;

}

, который я вызываю синхронно с методом, вызываемым из viewDidAppear.

    if ([self reachable]== YES) {
        ... do network stuff ...

, основанный на коде из Руководства по доступности для iOS 4

Мой вопрос: существует ли правильное использование Reachability, которое позаботится об этом?ошибка и справиться с отсутствием сети 3G или Wifi?Нужно ли создавать другой поток или что-то делать, чтобы удалить синхронный вызов?

Здесь, между прочим, находится журнал сбоев, который я вижу при сбое моего приложения, что наводит меня на мысль, что это синхронная / асинхронная проблема.


Application Specific Information:
(app name) failed to resume in time

Elapsed total CPU time (seconds): 3.280 (user 1.770, system 1.510), 33% CPU 
Elapsed application CPU time (seconds): 0.040, 0% CPU

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib          0x30747fbc kevent + 24
1   libsystem_info.dylib            0x30abec4e _mdns_search + 586
2   libsystem_info.dylib            0x30abfb72 mdns_addrinfo + 370
3   libsystem_info.dylib            0x30abfd68 search_addrinfo + 76
4   libsystem_info.dylib            0x30ac1bcc si_addrinfo + 1080
5   libsystem_info.dylib            0x30abd0b2 getaddrinfo + 78
6   SystemConfiguration             0x311b4256 __SCNetworkReachabilityGetFlags + 962
7   SystemConfiguration             0x311b4f1e SCNetworkReachabilityGetFlags + 98

Ответы [ 2 ]

4 голосов
/ 24 сентября 2011

В синхронном случае вас, вероятно, убивает сторожевой таймер iOS-приложений. Это связано с тем, что для проверки достижимости функции SCNetworkReachability необходимо выполнить поиск DNS, который может занять до 30 секунд. Если при проверке доступности в главном потоке (т. Е. В viewDidAppear) вы блокируете основной поток на потенциально долгое время, iOS считает, что ваше приложение зависло, и сторожевой таймер приложения убивает его через 20 секунд.

Apple даже предупреждает об этом в примере кода Reacahbility:

Пример кода доступа Apple: README

Просто используйте уведомления, как в примере приложения Reachability - оно работает хорошо и довольно просто, как только вы получаете шаблон проектирования NSNotificationCenter.

Удачи!

0 голосов
/ 15 июля 2011

Я решил свою проблему, настроив ее как асинхронную.Я вызываю такой метод

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSTimer *timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(loadData) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[pool release];

, а вызываемый метод выглядит примерно так

- (void)loadData {
    // check for reachability first before starting data load
    if ([self reachable]== NO) {
        // display error message that there is no internet connection, e.g.
        UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:@"Connection Error" message:@"Cannot load data.  There is no internet connection." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Retry",nil];
        [errorAlert show];
        [errorAlert release];
    } else {
        // do something to load data from internet ...      
    }

}

, используя тот же код достижимости, что и выше.используйте Reachability вот так - пример, который Apple дает, неполон.У меня этот код работал в готовом приложении в течение нескольких месяцев, и он был очень стабильным.

РЕДАКТИРОВАТЬ: Этот код больше не стабилен с iOS 5 - теперь он можетиногда происходит сбой из-за «активных утверждений за пределами допустимого времени».Apple обновила свою документацию и пример кода с тех пор, как я написал этот вопрос, поэтому я предлагаю перейти по ссылке в другом ответе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...