iOS-приложение зависает с NSConditionLock
У меня странная проблема с зависанием приложения в определенный момент. Я думаю, это связано с тем, как я использую NSConditionLock
,
Theres библиотека, которую мне дали использовать, которая состоит из серии вопросов опроса, но она работает таким образом, что она переходит непосредственно к последнему вопросу, не принимая ответы, следовательно, необходимо приостановить поток и принять ввод от пользователь.
Я не использовал его раньше, так что, может быть, кто-то может помочь, если я неправильно его реализую? Пожалуйста, дайте мне знать, если предоставленного кода недостаточно.
- (void)viewDidLoad
{
[super viewDidLoad];
//INITIALISE CONDITION LOCK WITH CONDITION 0
condition=[[NSConditionLock alloc]initWithCondition: 0];
}
- (IBAction)startPressed:(UIButton*)sender {
if (sender.tag == 1) {
//START BACKGROUND THREAD
surveyThread = [[NSThread alloc] initWithTarget:self selector:@selector(runProjecttest) object:nil];
[surveyThread start];
}
else
{
//DO SOME STUFF AND THEN UNLOCK
[condition unlockWithCondition:1];
}
}
- (void) runProjecttest:(AbstractTask *)rendertask
{
// DO STUFF AND SHOW UI ON MAIN THREAD, THEN LOCK
[self performSelectorOnMainThread:@selector(showUI:) withObject:task waitUntilDone:YES];
[condition lockWhenCondition: 1];
}
РЕДАКТИРОВАТЬ: Короче говоря, я хочу, чтобы Objc эквивалент этого фрагмента Java...
this.runOnUiThread(showUI);
try
{
//SLEEP
Thread.sleep(1000*60*60*24*365*10);
}
catch (InterruptedException e)
{
//WAKE
setResponse(at,showUI);
}
РЕДАКТИРОВАТЬ 2: метод ShowUI по запросу Пола.
[self removePreviousSubViews];
switch ([task getType]) {
case SingleChoiceType:
{
NSLog(@"SingleChoiceType");
isMultipleChoice = NO;
[self addSingleChoiceView:nil];
break;
}
case TextType:
{
NSLog(@"TextType");
self.txtTextType.keyboardType=UIKeyboardTypeDefault;
[self addTextTypeView:nil];
break;
}
...more cases
}
-(void)addTextTypeView:(NSSet *)objects
{
self.txtTextType.text = @"";
CGRect frame = self.txtQuestionType.frame;
// frame.size = [self.txtQuestionType sizeThatFits: CGSizeMake(self.txtQuestionType.frame.size.width, FLT_MAX)];
frame.size.height = [self textViewHeightForAttributedText:self.txtQuestionType.text andWidth:self.txtQuestionType.frame.size.width andTextView:self.txtQuestionType];
self.txtQuestionType.frame=frame;
self.textTypeView.frame = CGRectMake((self.view.frame.size.width - self.textTypeView.frame.size.width)/2, ( self.txtQuestionType.frame.origin.y+self.txtQuestionType.frame.size.height), self.textTypeView.frame.size.width, self.textTypeView.frame.size.height);
[self.view addSubview: self.textTypeView];
}
1 ответ
Я согласен с BryanChen, я думаю, у вас может быть другая проблема. Без подробностей о библиотеке опросов невозможно подтвердить, но если предположить, что это UIViewController, который принимает сенсорный ввод для прохождения ряда вопросов, трудно понять, почему это проблема с многопоточностью - она просто не должна развиваться без взаимодействия с пользователем.
Что в сторону, ваше использование NSCondtionLock
тоже не выглядит правильно.
По сути NSConditionLock
имеет NSInteger, который представляет текущее "условие", но просто подумайте о нем числа. Затем вы можете выполнить две основные операции:
lockWhenCondition:x
будет блокировать текущий поток, пока "условие" не станет "х" и блокировка не будет доступна. Затем он будет требовать блокировки.
unlockWithCondition:y
снимает блокировку и устанавливает условие в 'y'
Есть также методы для установки таймаутов (lockBeforeDate
) и попытаться получить блокировку без блокировки (tryLock
, tryLockWhenCondition
).
Для синхронизации двух потоков используется общая схема
- Инициализация Блокировка для условия "х"
- Тема 1
lockWhenCondition:x
-Этот поток может требовать блокировки, потому что это х - Тема 2
lockWhenCondition:y
- Этот поток будет заблокирован, потому что блокировка х - Тема 1 завершает работу,
unlockWithCondition:y
- Это позволит потоку 2 требовать блокировки и разблокировать этот поток
Ваш код выглядит странно, потому что вы запускаете поток в предложении if, но разблокируете в предложении else. Я бы подумал, что у вас будет что-то вроде -
-(IBAction)startPressed:(UIButton*)sender {
if (sender.tag == 1) {
//START BACKGROUND THREAD
surveyThread = [[NSThread alloc] initWithTarget:self selector:@selector(runProjecttest) object:nil];
[surveyThread start];
[condition:lockWithCondition:1]; // This will block until survey thread completes
[condition:unlockWithCondition:0]; // Unlock and ready for next time
}
}
- (void) runProjecttest:(AbstractTask *)rendertask
{
// DO STUFF AND SHOW UI ON MAIN THREAD, THEN LOCK
[condition lockWhenCondition: 0];
[self performSelectorOnMainThread:@selector(showUI:) withObject:task waitUntilDone:YES];
[condition unlockWithCondition:1];
}
НО это выглядит как рецепт для взаимоблокировки, потому что вы выполняете селектор showUI в главном потоке, который заблокирован, ожидая завершения потока опроса.
Что возвращает нас к вопросу, что делает showUI
делать и почему он пропускает прямо до конца?