Я пытаюсь получить данные из веб-сайта - xml. Все хорошо работает.
Но UIButton остается нажатым, пока данные XML не возвращаются и таким образом если существует проблема с интернет-сервисом, он, наклон быть исправленным и приложение фактически неприменим.
вот вызовы:
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if(!appDelegate.XMLdataArray.count > 0){
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[appDelegate GetApps]; //function that retrieves data from Website and puts into the array - XMLdataArray.
}
XMLViewController *controller = [[XMLViewController alloc] initWithNibName:@"MedGearsApps" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
Это хорошо работает, но как я могу сделать кнопки представления функциональными с застреванием. Другими словами, я просто хочу, чтобы UIButton и другой UIButtons были функциональной хитростью вещь работы в фоновом режиме.
Я слышал о performSelectorInMainThread, но я не могу поместить его для осуществления правильно
любая справка ценится :)
Вы плохо разбираетесь в потоковой модели и, вероятно, собираетесь выстрелить себе в ногу, если начнете добавлять асинхронный код, не понимая, что происходит на.
Написанный вами код выполняется в основном потоке приложения. Но когда вы думаете об этом, вам не нужно писать никакой функции main
- вы просто реализуете делегат приложения и обратные вызовы событий (например, обработчики касаний), и каким-то образом они запускаются автоматически, когда приходит время. Это не волшебство, это просто объект Какао, называемый Run Loop .
Цикл выполнения - это объект, который получает все события, обрабатывает таймеры (как в NSTimer
) и запускает ваш код. Это означает, что когда вы, например, делаете что-то, когда пользователь нажимает кнопку, дерево вызовов выглядит примерно так:
main thread running
main run loop
// fire timers
// receive events — aha, here we have an event, let’s call the handler
view::touchesBegan…
// use tapped some button, let’s fire the callback
someButton::touchUpInside
yourCode
Теперь yourCode
делает то, что вы хотите, и цикл выполнения продолжает работать. . Но когда ваш код занимает слишком много времени для завершения, например, в вашем случае, цикл выполнения должен подождать, и, следовательно, события не будут обрабатываться, пока ваш код не будет завершен. Это то, что вы видите в своем приложении.
Чтобы разрешить ситуацию, вам нужно запустить длинную операцию в другом потоке.Это не очень сложно, но, тем не менее, вам придется подумать о нескольких потенциальных проблемах. Запуск в другом потоке может быть таким же простым, как вызов performSelectorInBackground
:
[appDelegate performSelectorInBackground:@selector(GetApps) withObject:nil];
И теперь вы должны подумать о способе сообщить приложению, что данные были загружены, например, с помощью уведомления или вызова селектора на основной поток. Между прочим: хранение данных в делегате приложения (или даже использование делегата приложения для загрузки данных) - не очень элегантное решение, но это уже другая история.
Если вы все же выберете решение performSelectorInBackground
, обратите внимание на связанный вопрос об управлении памятью во вторичных потоках . Вам понадобится собственный пул автозапуска, чтобы не допустить утечки автоматически выпущенных объектов.
Обновление ответа через некоторое время - в настоящее время обычно лучше запускать код в фоновом режиме с помощью Grand Central Dispatch:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// No explicit autorelease pool needed here.
// The code runs in background, not strangling
// the main run loop.
[self doSomeLongOperation];
dispatch_sync(dispatch_get_main_queue(), ^{
// This will be called on the main thread, so that
// you can update the UI, for example.
[self longOperationDone];
});
});
Используйте метод NSURLConnection connectionWithRequest: delegate: . Это приведет к асинхронной отправке указанного запроса. Делегат должен ответить на соединение: didReceiveResponse: и будет отправлено это сообщение, как только ответ будет полностью получен.
Похоже, вы используете NSURLConnection внутри своего метода getApps. Если да, вам следует преобразовать его в асинхронный вызов.
Можно использовать фоновую операцию, которая попадает в очередь операций:
BGOperation *op = [[BGOperation alloc] init];
[[self operationQueue] addOperation:op];
[op release];
Я создал определенные "команды", которые выполняются в фоновом режиме:
@implementation BGOperation
# pragma mark Memory Management
- (BGOperation *)init
{
if ((self = [super init]) != nil)
/* nothing */;
return self;
}
- (void)dealloc
{
self.jobId = nil;
[super dealloc];
}
# pragma mark -
# pragma mark Background Operation
- (void)main
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[appDelegate GetApps];
[pool release];
return;
}
@end
После завершения может быть хорошей идеей послать уведомление в основной поток, потому что внутренняя база данных была изменена.