Делегирование NSURLConnection и многопоточность — iPhone

У меня есть класс, который обновляет два файла .plist в каталоге документов приложения через NSURLConnection. Класс действует как собственный делегат для NSURLConnection. Он работает правильно, когда я запрашиваю один файл, но терпит неудачу, когда я пытаюсь обновить два файла. Похоже ли, что я должен начать новый поток для каждого из сообщений getNewDatabase?

- (void)getAllNewDatabases {
    [self performSelectorOnMainThread:@selector(getNewDatabase:) withObject:@"file1" waitUntilDone:YES];
    [self performSelectorOnMainThread:@selector(getNewDatabase:) withObject:@"file2" waitUntilDone:YES];
}

- (BOOL)getNewDatabase:(NSString *)dbName
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSMutableString *apiString = [[NSMutableString alloc] initWithString:kAPIHost];
    [apiString appendFormat:@"/%@.plist",dbName];
    NSURLRequest *myRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:apiString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
    NSURLConnection *myConnection = [[NSURLConnection alloc] initWithRequest:myRequest delegate:self];
    [apiString release];
    if( myConnection )
    {
        //omitted for clarity here
    }
    [pool release];
}
//NSURLConnection delegate methods here ...

person FluffulousChimp    schedule 01.08.2009    source источник


Ответы (2)


Я нашел кое-что интересное с NSURLConnection и NSThread — поток будет жить только до тех пор, пока он выполняет метод, который вы вызываете из него.

В приведенном выше случае поток будет жить только до тех пор, пока getNewDatabase:(NSString *)dbName не завершится, поэтому любой из его методов делегата будет уничтожен до того, как они действительно успеют что-либо сделать.

Я нашел этот веб-сайт, который дает лучшее объяснение и решение проблемы

Я немного подправил его, чтобы у меня был настраиваемый тайм-аут, если он не завершился в заданный период времени (удобно, когда кто-то ходит между точками доступа).

    start = [NSDate dateWithTimeIntervalSinceNow:3];

    while(!isFinished && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode 
                                                  beforeDate:[NSDate distantFuture]]){

    if([start compare:[NSDate date]] == NSOrderedAscending){
        isFinished = YES;
    }
}
person James    schedule 01.08.2009
comment
Сообщение в блоге, на которое вы ссылаетесь, было перемещено — я думаю, это оно: sortedbits. com/nsurlconnection-в-собственном-потоке - person Martin Gjaldbaek; 11.06.2012

В настоящее время в предоставленном вами коде getNewDatabase: выполняется в основном потоке вашего приложения. Таким образом, проблема в данном конкретном случае заключается в чем-то другом, а не в жизненном цикле потока, как заметил Джеймс в своем случае.

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

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

Маркус Зарра также написал руководство это демонстрирует, насколько легко включить и использовать NSOperationQueue для простых фоновых операций.

person Sean Patrick Murphy    schedule 01.08.2009
comment
Спасибо, тем временем я разветвил версию, которая делает именно это с NSOperation / NSOperationQueue. Теперь работает отлично. - person FluffulousChimp; 01.08.2009