2009-12-04 1 views
2

Как установить таймаут, когда я разбираю фид с помощью initWithContentsOfURL. Иногда наши каналы возвращают пустой ответ, а затем он просто попытается разобрать фид навсегда. Я хочу установить тайм-аут в 30 секунд или около того, чтобы вывести UIAlertView, а затем попытаться повторно обработать фид.NSXMLParser initWithContentsOfURL timeout

NSURL *feedURL = [[NSURL alloc] initWithString:URL]; 
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:feedURL]; 
    [parser setDelegate:self]; 
    [parser setShouldProcessNamespaces:NO]; 
    [parser setShouldReportNamespacePrefixes:NO]; 
    [parser setShouldResolveExternalEntities:NO]; 

    [parser parse]; 

ответ

3

Первый подход:используя отсроченную селектор

Вероятно, самый простой способ сделать это состоит в использовании метода performSelector:withObject:afterDelay: NSObject в. Вы можете определить, какой метод parsingDidTimeout как таковые:

- (void)parsingDidTimeout { 
    if(self.parsingDidComplete == NO) { 
     [self.parser abortParsing]; 
     // Create your error and display it here 

     // Try the fetch and parse again... 
    } 
}

Это требует, чтобы вы повесите на анализатор как переменный экземпляр (self.parser), так что вы можете отменить его от выбранного метода определения. Это также требует, чтобы делегат вашего парсера отслеживал, закончил ли парсер (self.parsingDidComplete), по умолчанию может быть NO и установить YES в методе делегата parserDidEndDocument:). Это позволит избежать прерывания успешного анализа. После того, как это будет сделано, все это занимает простого

[self performSelector:@selector(parsingDidTimeout) withObject:nil afterDelay:30];

и через тридцать секунд, ваш код парсинг-прерывание будет вызван, и вы можете делать все, что вам нужно сделать.

Второй подход:с помощью таймера

Вы могли бы сделать весь этот подход (возможно) проще в методе таймаута с помощью NSTimer вместо вызова метода NSObject. Таким образом, если парсер успешно завершит работу, вы можете просто аннулировать таймер, что позволит вам исключить пункт if в методе parsingDidTimeout (и, как результат, также избавиться от ivar BOOL). Инициализации таймера будут выглядеть следующим образом:

NSTimer *timer = [NSTimer timerWithTimeInterval:30.0 
             target:self 
             selector:@selector(parsingDidTimeout) 
             userInfo:nil 
             repeats:NO]; 
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
+1

Проблема со вторым подходом является то, что таймер прибавляется к текущему цикла выполнения. Процесс парирования является синхронным, а не асинхронным. Если считывание останавливается и не выполняется тайм-аут, тогда поток занят и поэтому никогда не будет доступен для выполнения таймаута. При этом я предпочитаю второе решение, потому что таймер может быть отменен, если чтение будет успешным. –

1

не отвечает на вопрос направления, но вы бы иметь полный контроль над запросом и ответ циклом (а также асинхронность без дополнительных потоков), если вы использовали NSURLConnection для загрузки данные. Вот что делает initWithContentsOfURL:, под обложками.

0

Swift 3 Пример использования NSTimer ака Timer

func startParseTimeoutTimer() { 
    Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { (_) in 
     if (self.busy) { 
      self.parser?.abortParsing() 
      self.parser = nil 
      print("Show UI as NOT busy; we aborted for timeout \(Thread.current.isMainThread)") 
     } 
    } 

}