#objective-c #ios #cocoa-touch
#objective-c #iOS #cocoa-touch
Вопрос:
У меня есть таймер, который я использую для проверки веб-адреса каждые 11 секунд. Я использую ASIHTTPRequest для установки делегата, который сообщает ответ от веб-сервера. Если я получу искомый ответ, я хочу обновить пользовательский интерфейс. К сожалению, это не работает, я подозреваю, потому что я не обновляю пользовательский интерфейс из потока пользовательского интерфейса.
Код для запуска и обработки таймера:
- (void)startTimer {
BOOL timerStarted = false;
BOOL running = false;
BOOL readyToProcess = false;
if(!timerStarted){
running = true;
timerStarted = true;
readyToProcess = true;
autosaveTimer = [[NSTimer scheduledTimerWithTimeInterval:11
target:self
selector:@selector(processWebCheckTimer:)
userInfo:nil
repeats:YES] retain];
}
}
- (void)processWebCheckTimer:(NSTimer*)theTimer {
if ([VariableStore sharedInstance].success < 1) { //conversion not done, check again
NSURL *url = [NSURL URLWithString:@"WEBSERVERURLHERE"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:oc_request forKey:@"queue"];
[request setRequestMethod:@"POST"];
[request setDelegate:self];
[request startAsynchronous];
}
}
Проверьте ответ и обновите пользовательский интерфейс:
- (void)requestFinished:(ASIFormDataRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
if ([responseString rangeOfString:@"uccessfully converted"].location != NSNotFound) {
[self performSelectorOnMainThread:@selector(threadStopAnimatingTwo:) withObject:nil waitUntilDone:YES]; //DOESNT WORK
[autosaveTimer invalidate];
}
}
Функция для обновления пользовательского интерфейса:
- (void) threadStopAnimatingTwo:(id)data {
NSLog(@"stop animating two");
[loadingTwo stopAnimating];
[labelTwo setTextColor:[UIColor lightGrayColor]];
}
Комментарии:
1. Почему вы создаете таймер, который повторяется, а затем аннулируете его?
2. Я аннулирую только после того, как получу то, что проверяю, в противном случае он проверяет снова через 11 секунд. В любом случае, это не имеет значения, потому что я знаю
threadStopAnimatingTwo
, что работает, он просто не запускается в правильном потоке, потому что пользовательский интерфейс не меняется.3. Проверить, в каком потоке выполняется строка кода, легко. 1) Поставьте точку останова в рассматриваемой строке. 2) Запускайте до точки останова. 3) В меню выберите Вид-> Навигаторы-> Показать навигатор отладки там вы сможете увидеть свой стек вызовов, разделенный потоком.
4. Код для обновления пользовательского интерфейса выполняется в потоке 1 в соответствии с навигатором отладки. Есть идеи, почему пользовательский интерфейс на самом деле не обновляется? Если я вызываю ту же функцию,
ViewDidLoad
она работает, поэтому я знаю, что в коде обновления пользовательского интерфейса нет ничего плохого.5. В threadDtopAnimatingTwo попробуйте NSLog (@»loadingTwo = %@»,loadingTwo) Это проверит, на что направлен ваш указатель.
Ответ №1:
Попробуйте обновить пользовательский интерфейс, используя свойства, а не переменные экземпляра.
Например:
- (void) threadStopAnimatingTwo:(id)data {
NSLog(@"stop animating two");
[self.loadingTwo stopAnimating];
[self.labelTwo setTextColor:[UIColor lightGrayColor]];
}
Комментарии:
1.
self.loadingTwo
также подходитnull
. Возможно лиself
, что это не то, что обычно, поскольку оно находится внутри делегата ответа ASIHTTPRequest?2. Нет, но ваша формулировка меня беспокоит. Насколько я понимаю, threadStopAnimatingTwo — это метод вашего класса контроллера представления, который просто вызывается ASIHTTPRequest как метод делегирования. Если это правильно, то единственным оставшимся объяснением может быть то, что что-то устанавливает для ваших компонентов пользовательского интерфейса значение nil после метода viewDidLoad . Просто для справки, ни для одного компонента пользовательского интерфейса не должно быть установлено значение nil в любом месте перед viewDidUnload. Попробуйте выполнить поиск в любом месте, где для любого компонента пользовательского интерфейса установлено значение nil.
3. По какой-либо причине любой компонент пользовательского интерфейса, к которому обращаются из методов делегирования ASIHTTP, имеет значение null. Я «решил» проблему, сохранив компоненты пользовательского интерфейса, которые мне нужны для использования в делегировании глобалам в viewDidLoad.
4. Self.properties являются глобальными. Что-то все еще не так, и я знаю, что вы знаете, основываясь на «решаемых» кавычках. Вы пробовали вызывать эту функцию где-нибудь еще, кроме viewDidLoad?
Ответ №2:
// можете ли вы добавить журнал? печать?
NSLog(@"execute performSelectorOnMainThread");
[self performSelectorOnMainThread:@selector(threadStopAnimatingTwo:)
withObject:nil
waitUntilDone:YES]; //DOESNT WORK
Комментарии:
1. Да, если я добавлю этот оператор log, он появится в выходных данных. То же самое для
threadStopAnimatingTwo
функции. Я знаю, что обе функции запущены, но пользовательский интерфейс никогда не обновляется.
Ответ №3:
Оказывается, я создавал новый экземпляр моего контроллера представления, когда мне это было не нужно. Поскольку я создал новый экземпляр контроллера представления, [self.loadingTwo]
сослался на null
Компонент пользовательского интерфейса.