2013-08-29 3 views
6

Многие люди задают вопрос с похожим названием, но очень разные цели:dispatch_get_current_queue() устарел, есть ли альтернатива безопасному CoreData?

CoreData требует, что вы следить за вашей текущей очереди, текущей нити и текущей NSOperationQueue (если вы являетесь NSOperation) , если вы разрешаете вызовам методов из других классов (что, по умолчанию, разрешает каждый класс). Об этом нет «майбе»: это жесткое требование.

Это нормально, и в целом легко обеспечить:

NSAssert([NSThread currentThread].isMainThread || myPrivateQueue == dispatch_get_current_queue(), @"You tried to call this method from an external thread, or a queue other than my internal private queue. That's not legal, and will cause data corruption"); 

... за исключением того, что Apple, пошел и устаревшее dispatch_get_current_queue(), по-видимому «, потому что люди злоупотребляют его, чтобы вокруг не хватает функциональности в НОД/бит GCD, которые они не понимали ».

NB: мое использование dispatch_get_current_queue() выше, как представляется, является правильным и не оскорбительным, судя по комментарию заголовка Apple: все дело в том, что я проверяю, что очередь является частной, которую я создал (что утверждает Apple допустимое использование).

Оставляя в стороне мудрость обесценить что-то просто из-за недостатков в его реализации :(... кто-нибудь нашел обходное решение для этого, которое было удалено Apple. В частности: с CoreData вам нужно отслеживать очередь - есть ли другой способ сделать это?

(это важно, потому что: с помощью CoreData, если вы позволите чему-то случайно вызвать такой метод, вы не получите «краху», вы получите «повреждение данных», которое будет отображаться на . какой-то момент в будущем, когда уже слишком поздно, чтобы исправить это ")

+0

Я использовал 'dispatch_queue_set_specific()' и 'dispatch_get_specific()' для приложения, которое я спросил здесь: http://stackoverflow.com/questions/12806506/how-can-i-verify-that- i-am-running-on-a-given-gcd-queue-without-use-dispatch-g, и он отлично работает, чтобы идентифицировать определенные очереди. В комментарии Джоди о ответе упоминается использование чего-то подобного в Core Data. –

+0

@BradLarson dispatch_get_specific() очень интересно, спасибо. Я не уверен, что произойдет, если вы вызовете его, когда вы не находитесь внутри блока (в правильном исполнении вы бы это сделали, но я хотел бы знать, что происходит, когда он идет не так, потому что это настройка, которую я пытаюсь ловить/утверждать/лог против) – Adam

+0

Я не знаю, что это в блоке. Все, что он тестирует, - это ключ, назначенный конкретной очереди, в которой этот код работает. Как я покажу там, я использую это для функции, которая гарантирует синхронное выполнение кода в конкретной очереди, либо путем синхронной отправки блока в очередь, либо путем непосредственного запуска кода, если он уже находится в этой очереди. –

ответ

4

performBlock всегда запустить его в правильном потоке Просто используйте:

[yourManagedObjectContext performBlock:^{ 
//do your stuff here 
}]; 

Вам больше не нужен контекст текущего трека, потому что ваш MOC знает, какая нить запускает этот MOC на первом месте. Когда вы используете performBlock или performBlockAndWait, вы в безопасности.

+0

Хорошая идея, но, похоже, проблемы с блокировкой потоков и производительность в сложных ситуациях - под «проблемами» Я имею в виду «возможно, проблемы с CoreData, возможно, также ошибки в нашей кодовой базе, возможно, вместе». Один из моих первых шагов состоял в том, чтобы начать утверждать либерально, чтобы выяснить, почему иногда «CoreData висит на десятки секунд на мьютексе, который кажется неоспоримым». – Adam

+0

... так что я пытаюсь удалить нашу уверенность в том, что «всегда выполняйте блокировку для всего» и узнайте, что на самом деле происходит/не происходит. – Adam

+0

«Always' performBlock:« для всего »- это очень рекомендуемый способ делать вещи AFAICT. 'dispatch_get_current_queue()' в значительной степени бесполезен из-за того, как работает libdispatch - существует небольшое количество «глобальных» очередей и других очередей, в конечном итоге целевые операции выполняются в этих очередях. Это делает бесполезным вызов, потому что это текущая очередь? Тот, на который он был заключен, или глобальная очередь, на которой он выполняется. Очередь - это арбитр той очереди, в которой вы находитесь. В этом случае 'performBlock:' является enqueuer, и это единственный способ узнать, что вы в этой очереди. – ipmcc

0

В моем конкретном случае, я заменил все performBlock призывов:

  1. двигающихся все действия CoreData к одному классу
  2. создания собственной dispatch_queue
  3. переходящей всем моим внутренним вызовов в единый звоните
  4. единственный вызов заворачивается в dispatch_async ((частные внутренние очереди))
    1. ... и первое, что он делает внутри dispatc h является «if (self.privateMOC == nil)» ...и создает локальный MOC, гарантируя, что MOC только когда-либо доступен и creatd на этой одной очереди

произошли две вещи:

  1. мьютекс/замок висит все исчезли (хотя это может быть совпадением - я сообщу позже, если окажется, что замки по-прежнему находятся в тупике)
  2. Производительность выглядит заметно лучше, чем при выполнении. Блокировка: используется везде
    1. ПРИМЕЧАНИЕ. У нас было много вызовов executeBlock, и они делали это часто (конфиденциальные данные, которые должны изменять содержимое MOC CoreData на умеренно высокой частоте). Я не знаю, если это будет заметная разница в нормальном приложении

... так, сейчас, для моих целей: это оказалось хорошим решением. Я не верю, что это «правильный» общий ответ на этот вопрос, но ... я рекомендую его всем, кто считает, что «performBlock» - это меньше панацеи, чем кажется.

Смежные вопросы