(Два редактирования следуют за исходным текстом этого вопроса, оба из которых довольно радикально изменяют вопрос. Не зацикливайтесь на первой части этого - хотя это полезно для контекстуальных целей, я почти исключил исходную проблему Я спрашивал о.)
Как вы можете видеть из названия, я загнал себя в угол, и у меня есть несколько вещей, работающих против меня...
В подклассе UIViewController, который управляет большим и сложным представлением. Одна его часть — это UIWebView, который содержит вывод веб-запроса, который мне пришлось построить и выполнить, а также вручную собрать HTML-код. Поскольку для запуска требуется секунда или две, я перевел его в фоновый режим, вызвав self performSelectorInBackground:. Затем из этого метода, который я вызываю, я использую self performSelectorOnMainThread:, чтобы вернуться на поверхность стека потоков, чтобы обновить UIWebView тем, что я только что получил.
Как это (которое я сократил, чтобы показать только соответствующие проблемы):
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
//then get mapquest directions
NSLog(@"Got called to handle new location!");
[manager stopUpdatingLocation];
[self performSelectorInBackground:@selector(getDirectionsFromHere:) withObject:newLocation];
}
- (void)getDirectionsFromHere:(CLLocation *)newLocation
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CLLocationCoordinate2D here = newLocation.coordinate;
// assemble a call to the MapQuest directions API in NSString *dirURL
// ...cut for brevity
NSLog(@"Query is %@", dirURL);
NSString *response = [NSString stringWithContentsOfURL:[NSURL URLWithString:dirURL] encoding:NSUTF8StringEncoding error:NULL];
NSMutableString *directionsOutput = [[NSMutableString alloc] init];
// assemble response into an HTML table in NSString *directionsOutput
// ...cut for brevity
[self performSelectorOnMainThread:@selector(updateDirectionsWithHtml:) withObject:directionsOutput waitUntilDone:NO];
[directionsOutput release];
[pool drain];
[pool release];
}
- (void)updateDirectionsWithHtml:(NSString *)directionsOutput
{
[self.directionsWebView loadHTMLString:directionsOutput baseURL:nil];
}
Все это прекрасно работает, ЕСЛИ Я не отказался от этого контроллера представления до того, как CLLocationManager нажмет на свой метод делегата. Если это происходит после того, как я уже покинул это представление, я получаю:
2010-06-07 16:38:08.508 EverWondr[180:760b] bool _WebTryThreadLock(bool), 0x1b6830: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Несмотря на то, что это говорит, я могу неоднократно вызывать этот сбой, когда я отступаю слишком рано. Я совсем не уверен, что попытка обновления пользовательского интерфейса из фонового потока действительно проблема; Я думаю, что мой UIWebView освобожден. Я подозреваю, что тот факт, что я только что был в фоновом потоке, заставляет среду выполнения подозревать, что что-то не так, но я совершенно уверен, что это не так.
Итак, как мне сказать CLLocationManager, чтобы он не беспокоился об этом, когда я отказываюсь от этого представления? Я попробовал [self.locationManager stopUpdatingLocation] внутри моего метода viewWillDisappear, но это не помогло.
(Между прочим, API-интерфейсы MapQuest ФАНТАСТИЧЕСКИЕ. НАМНОГО лучше, чем все, что предлагает Google. Я не могу рекомендовать их достаточно высоко.)
РЕДАКТИРОВАТЬ 1:
Это стало еще страннее. Я на самом деле изолировал, где происходит сбой, и это внизу -(void) dealloc. Если я закомментирую [super dealloc], я не сбой! Но я не могу «зайти» в [super dealloc], чтобы посмотреть, что происходит в суперклассе, он просто падает и перестает со мной разговаривать.
Вот трассировка стека:
#0 0x3018c380 in _WebTryThreadLock ()
#1 0x3018cac8 in _WebThreadAutoLock ()
#2 0x3256e4f0 in -[UITextView dealloc] ()
#3 0x323d7640 in -[NSObject release] ()
#4 0x324adb34 in -[UIView(Hierarchy) removeFromSuperview] ()
#5 0x3256e4a8 in -[UIScrollView removeFromSuperview] ()
#6 0x3256e3e4 in -[UITextView removeFromSuperview] ()
#7 0x324ffa24 in -[UIView dealloc] ()
#8 0x323d7640 in -[NSObject release] ()
#9 0x3256dd64 in -[UIViewController dealloc] ()
#10 0x0000c236 in -[EventsDetailViewController dealloc] (self=0x1c8360, _cmd=0x3321ff2c) at /Users/danielray/Documents/Xcode Projects/EverWondr svn/source/obj-c/Classes/EventsDetailViewController.m:616
#11 0x323d7640 in -[NSObject release] ()
#12 0x336e0352 in __NSFinalizeThreadData ()
#13 0x33ad8e44 in _pthread_tsd_cleanup ()
#14 0x33ad8948 in _pthread_exit ()
#15 0x33731f02 in +[NSThread exit] ()
#16 0x336dfd2a in __NSThread__main__ ()
#17 0x33ad8788 in _pthread_body ()
#18 0x00000000 in ?? ()
Кроме того, теперь ясно, что ошибка возникает при нажатии кнопки «Назад» во время работы [self getDirectionsFromHere]. Окно для этого — пока мы ждем возврата вызова stringWithContentsOfURL.
РЕДАКТИРОВАТЬ 2:
Итак, заметив [UITextView dealloc] в верхней части этого стека, я понял, что у меня есть только один UITextView в этой иерархии представлений, поэтому я закомментировал выпуск этого объекта UITextView в -(void) dealloc. При следующем сбое в этом месте следа было [UIWebView dealloc]. Хм! Перемена! Итак, я закомментировал свой единственный выпуск webView в методе Dealloc... и теперь у меня не происходит сбой. Это не решение, потому что, насколько я могу судить, сейчас я просто сливаю эти два объекта, но это, безусловно, интересно. Или, по крайней мере, я надеюсь, что это для кого-то, потому что я в полной растерянности.