sizeWithFont в MultiThread Crash!
Сбой sizeWithFont в многопоточности, это информация отладки:
1 0x00a0df8e in icu::RuleBasedBreakIterator::handleNext
2 0x00a0daff in icu::RuleBasedBreakIterator::next
3 0x00a0d174 in icu::RuleBasedBreakIterator::following
4 0x35879719 in WebCore::nextBreakablePosition
5 0x3587842a in -[NSString(WebStringDrawing) _web_drawInRect:withFont:ellipsis:alignment:lineSpacing:includeEmoji:measureOnly:]
6 0x35877da3 in -[NSString(WebStringDrawing) _web_sizeInRect:withFont:ellipsis:lineSpacing:]
7 0x3090d238 in -[NSString(UIStringDrawing) sizeWithFont:constrainedToSize:lineBreakMode:lineSpacing:]
8 0x3090cee3 in -[NSString(UIStringDrawing) sizeWithFont:constrainedToSize:lineBreakMode:]
теперь я решаю ошибку с помощью объекта NSLock, перед использованием этой функции я буду блокировать этот объект, а после этого разблокировать его
но я думаю, что должно быть более лучшее решение!
и я обнаружил, что эта ошибка появляется только тогда, когда объект NSString для этой функции в обоих потоках является многострочным текстом
3 ответа
Как правило, вы не должны вызывать методы UIKit [1] из отдельного потока. Неважно, если вы берете замки, это не стартер.
Когда вы используете многопоточные приложения, вам нужно убедиться, что любой код, который касается любых объектов UIKit, выполняется в главном потоке. Это достигается с помощью executeSelectorOnMainThread:withObject:waitUntilDone: метод, который вызывает данный селектор в основном потоке:
Или в MonoTouch: foo.InvokeOnMainThread (делегат {ваш_код_ здесь});
[1] В iOS 4.0 правило смягчено для нескольких API.
Форматирование, пожалуйста.
"Решение" многопоточной задачи путем размещения случайных блокировок вокруг объектов никогда не является правильным ответом. Никогда не. Многопоточность требует системного дизайна вашего приложения.
Если блокировка "устраняет" проблему, показывает, что вы заблокировали и как это важно для оценки ситуации.
Еще некоторые симптомы будут полезны. Кодекс, в частности. Код в ваших вопросах очень полезен.
Учитывая отсутствие доказательств, я бы поспорил, что вы изменяете строку в одном потоке, пытаясь получить размер в другом. Или объект освобождается в одном потоке, в то же время используя его в другом. Или вы управляете объектом из вторичного потока, который не является потокобезопасным.
Я думаю, что executeSelectorOnMainThread:withObject:waitUntilDone: правильно,
Раньше я использовал операцию для вычисления размера текста и использовал waitUntilAllOperationsAreFinished в главном потоке для ожидания возврата операции,
Но если я также использую executeSelectorOnMainThread: withObject: waitUntilDone в операции, и установите для параметра waitUntilDone значение Yes(потому что мне нужен результат)
Основной поток будет застрял
Поэтому теперь я удаляю waitUntilAllOperationsAreFinished и использую асинхронный объект, чтобы гарантировать, что операция не начнется, пока предыдущий не остановился
[md removeAllObjects];
[md setObject:subString forKey:@"text"];
[md setObject:[NSNumber numberWithInt:view_w ] forKey:@"width"];
[md setObject:[NSNumber numberWithInt:height_left + font_h ] forKey:@"height"];
[self performSelectorOnMainThread:
@selector(calculateTextRegion:)
withObject:md
waitUntilDone:YES];
CGSize stringSize = textRegion;