NSLog работает в основном потоке (?) Блокирует основной поток, когда строка слишком велика?

Мне нужно отправить некоторые оставшиеся данные на сервер при запуске моего приложения, поэтому в

applicationDidFinishLaunching

Я вызываю метод, который преобразует некоторые объекты Core Data в текст JSON и отправляет его на сервер. Иногда приложение вылетает, потому что:

xxxxxx не удалось запустить вовремя

Моя первая мысль заключается в том, что я делаю что-то, когда приложение запускается, что блокирует основной поток, затем я понял, что это может быть не проблема, так как я использую NSURLConnection для отправки данных, которые являются асинхронными и не должны блокировать основной поток, после некоторого тестирования я обнаружил, что когда данные большие, приложение легче сломать, поскольку соединение асинхронное, единственный подозрительный код - это когда я создал текст JSON из объектов Core Data, я использую NSLog для его печати, и я пытался использовать жестко закодированный большой файл json, он всегда падает, если я закомментирую строку NSLog, он не падает.

Судя по сценарию, интересно:

  1. Я думал, что NSLog работает в основном потоке независимо от того, в каком потоке он вызывается? Затем я нашел в документе Apple:

Вывод из NSLogv сериализуется, поскольку только один поток в процессе может одновременно выполнять запись/регистрацию, описанную выше. Все попытки записи/регистрации сообщения завершаются до того, как следующий поток сможет начать свои попытки.

означает ли это, что даже он находится не в основном потоке, но регистрирует какую-то длинную строку, которая приводит к блокировке основного потока?

  1. Есть ли ограничения (теоретические, практические) на размер строки для NSLog? Жестко закодированный файл JSON имеет размер 150 КБ.

Большое спасибо!


person hzxu    schedule 10.09.2012    source источник
comment
Когда я воспроизвожу это и запускаю режим отладки, XCode зависает, а курсор превращается в радужный счетчик, мне приходится «принудительно отключать» XCode.   -  person hzxu    schedule 10.09.2012
comment
Какого черта вы пытаетесь записать 150 КБ? Это совершенно абсурдно.   -  person Lily Ballard    schedule 10.09.2012


Ответы (2)


Используйте очередь GCD и выгружайте журналы асинхронно.

Грубо говоря, вам нужно создать последовательную очередь:

lqueue = dispatch_queue_create("com.example.logging", NULL)

Запишите журнал, используя его:

dispatch_async(lqueue, ^{ /* write log here */ })

Я не проверял, но вместо NSLog вам, вероятно, понадобится использовать ASL (семейство функций asl_*).

Или, что еще лучше, просто используйте какое-нибудь решение, например https://github.com/robbiehanson/CocoaLumberjack, которое уже делает все это и многое другое.

person djromero    schedule 10.09.2012

Я думаю, что ваше приложение убивает сторожевой таймер iOS. Если вы просмотрите свои журналы ошибок, вы должны увидеть код 0x8badf00d. По сути, сторожевой таймер наблюдает за запуском и остановкой приложений, и если они занимают слишком много времени, он их убивает. Одним из отслеживаемых методов является метод applicationDidFinishLaunching. Нет документации о том, как долго ваше приложение должно запускаться, но это всего несколько секунд.

Что вам нужно сделать, так это переместить свой код в другой метод или в фоновый поток. applicationDidFinishLaunching должен завершиться настолько быстро, насколько это возможно.

Поищите здесь 0x8badf00d, и вы найдете много обсуждений по этому поводу и способов организации вашего кода.

person drekka    schedule 10.09.2012