Для чего используется PerformBlock: NSManagedObjectContext?

В iOS 5 у NSManagedObjectContext есть пара новых методов, performBlock: и performBlockAndWait:. Для чего на самом деле используются эти методы? Что они заменяют в старых версиях? Какие блоки должны быть переданы им? Как решить, что использовать? Если у кого-то есть примеры их использования, было бы здорово.


person nevan king    schedule 29.03.2012    source источник
comment
Вы имели в виду NSManagedObjectContext?   -  person MikeG    schedule 04.04.2012
comment
Я почти уверен, что он это сделал. Возможно, Неван может предложить это по адресу: stackoverflow.com/tags/nsmanagedobjectcomplex/synonyms.   -  person Bjinse    schedule 10.04.2012
comment
Исправил орфографическую ошибку, спасибо за наводку.   -  person nevan king    schedule 11.04.2012


Ответы (2)


Методы performBlock: и performBlockAndWait: используются для отправки сообщений вашему экземпляру NSManagedObjectContext, если MOC был инициализирован с помощью NSPrivateQueueConcurrencyType или NSMainQueueConcurrencyType. Если вы делаете что-либо с одним из этих типов контекста, например, устанавливаете постоянное хранилище или сохраняете изменения, вы делаете это в блоке.

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

performBlockAndWait: также добавит блок в резервную очередь и запланирует его запуск в собственном потоке. Однако блок не вернется, пока блок не завершит выполнение. Если вы не можете двигаться дальше, пока не узнаете, прошла ли операция успешно, то это ваш выбор.

Например:

__block NSError *error = nil;
[context performBlockAndWait:^{
    myManagedData.field = @"Hello";
    [context save:&error];
}];

if (error) {
    // handle the error.
}

Обратите внимание: поскольку я сделал performBlockAndWait:, я могу получить доступ к ошибке за пределами блока. performBlock: потребует другого подхода.

Из примечаний к выпуску основных данных iOS 5 :

NSManagedObjectContext теперь обеспечивает структурированную поддержку параллельных операций. Когда вы создаете контекст управляемого объекта с помощью initWithConcurrencyType:, у вас есть три варианта ассоциации его потока (очереди).

  • Ограничение (NSConfinementConcurrencyType).

    Это значение по умолчанию. Вы обещаете, что контекст не будет использоваться никаким потоком, кроме того, в котором вы его создали. (Это точно такое же требование к многопоточности, которое вы использовали в предыдущих выпусках.)

  • Частная очередь (NSPrivateQueueConcurrencyType).

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

  • Основная очередь (NSMainQueueConcurrencyType).

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

person MikeG    schedule 03.04.2012
comment
Спасибо за ответ. performBlockAndWait: не блокирует основной поток, не так ли? Сбивает с толку то, что его можно присоединить к основному циклу выполнения, но у него есть имя, из-за которого кажется, что оно заставляет вас ждать. - person nevan king; 11.04.2012
comment
Кроме того, что такое резервная очередь и длительные операции сохранения. Извините за все вопросы, я понятия не имею о треде. - person nevan king; 11.04.2012
comment
@MikeG Я думаю, что у вас все может быть наоборот (или я ошибся, когда читаю это). PerformBlockAndWait заблокирует любой поток, из которого он вызывается из — основной или другой — и ему все равно, с каким потоком связан MOC. Или я неправильно вас понял? - person RonLugge; 06.09.2012
comment
@RonLugg, спасибо, что позвал меня. Я сейчас читаю так, как вы читаете. - person MikeG; 06.09.2012
comment
Если PerformBlockAndWait: вызывается из основного потока, он блокирует основной поток до тех пор, пока блок не завершится. long persist расплывчато, но учтите, что сохранение данных на диск может быть более длительной операцией, чем сохранение тех же данных в контексте памяти. (кредит @RonLugge за указание на неверную, вводящую в заблуждение информацию в исходном комментарии) - person MikeG; 06.09.2012
comment
Если PerformBlockAndWait заблокирует вызываемый им поток, зачем нам его использовать? Почему бы не использовать coredata как обычно? - person user4951; 05.10.2012
comment
мне нужно создать свой ManagedObject в peformBlock? - person thierryb; 12.02.2013
comment
Но что, если я обращаюсь к контексту из правильного потока, из того, где он был инициализирован? Мне нужно использовать performBlock или performBlockAndWait или я могу сделать так же, как раньше? - person Fábio Oliveira; 15.04.2013
comment
@JimThio зачем использовать PerformBlockAndWait ... потому что иногда вам нужно что-то получить из основных данных, возможно, что-то сделать с объектом, а затем обработать. PerformBlock вернется немедленно, так как он просто планирует работу в очереди контекста. Если эта работа выполняется в фоновом потоке и фоновом контексте, вам необходимо убедиться, что работа выполняется в правильной очереди, что и делает метод PerformBlock. Помните, что очередь — это не поток, и очередь может работать с любым количеством потоков. - person bandejapaisa; 02.05.2013
comment
Потрясающий ответ. Спасибо! - person edhnb; 10.07.2013
comment
Насколько я понимаю, PerformBlockAndWait работает в потоке вызывающего абонента. - person Brad Thomas; 25.11.2013
comment
Может ли кто-нибудь очистить блок, он не вернется, пока блок не завершит выполнение - person marciokoko; 07.02.2014
comment
@marciokoko: -performBlockAndWait: не вернется, пока ^{block} не завершит выполнение. Она ведет себя так же, как и любая старая добрая вложенная подпрограмма. Его выполнение является синхронным. - person SwiftArchitect; 11.04.2014
comment
@MikeG Я не уверен, должен ли я обернуть все свои модификации сущности в performBlock или только в часть сохранения? - person Bigood; 13.10.2015
comment
Обратите внимание, что, поскольку я выполнил PerformBlockAndWait:, я могу получить доступ к ошибке вне блока. Поскольку ошибка была объявлена ​​с помощью __block, вы можете получить к ней доступ вне блока. PerformBlock: потребуется другой подход. Вы имеете в виду, что, поскольку PerformBlock: выполняется асинхронно, доступ к ошибке за пределами блока будет игрой перемен: может быть ошибка, но не в тот момент, когда вы обращаетесь к указателю. - person Elise van Looij; 01.06.2017

Они позволяют вам получить доступ к одним и тем же managedObjectContext потокам.

Я не совсем уверен, что я прав, но я использую это так.

Вы используете performBlockAndWait как "обычный". Вам это не нужно, если вы выполняете manageObjectContext только в одном потоке. Если вы выполняете его во многих потоках, тогда да, вам понадобится performBlock.

Итак, если вы находитесь в основном потоке, вам не нужно делать performBlockAndWait для основного managedObjectContext. По крайней мере у меня нет и у меня все хорошо.

Однако, если вы получите доступ к этому managedObjectContext в других потоках, тогда да, вам нужно будет сделать performBlockAndWait.

Такова цель performBlock и performBlockAndWait.

Кто-нибудь, пожалуйста, поправьте меня, если я ошибаюсь здесь. Конечно, если вы получаете доступ к контексту только в одном потоке, вы можете просто использовать значение по умолчанию.

person user4234    schedule 22.11.2012
comment
Эти два метода связаны с поведением выполнения инструкций в потоке, в котором вы их вызываете. Один блокирует вызывающий поток в ожидании возврата, другой — нет (вызов возвращается немедленно, даже если работа все еще выполняется). Либо можно вызвать из любого потока. - person Bill Patterson; 16.03.2013
comment
-1: Этот ответ просто неверен. Начнем с документации по NSManagedObjectContext: Core Data uses thread (or serialized queue) confinement to protect managed objects and managed object contexts. A consequence of this is that a context assumes the default owner is the thread or queue that allocated it—this is determined by the thread that calls its init method. You should not, therefore, initialize a context on one thread then pass it to a different thread. Таким образом, NSManagedObjectContexts НЕ являются потокобезопасными, и вы не можете получить к ним доступ через потоки. - person JRG-Developer; 05.04.2013
comment
Кроме того, эти методы связаны с параллелизмом (обработка synchronous или asynchronous). См. Ответ от @MikeG и соответствующие комментарии для обсуждения этого вопроса. - person JRG-Developer; 05.04.2013
comment
@ JRG-Developer Я думаю, вы действительно можете получить доступ к NSManagedObjectContexts между потоками. Чего вы не можете сделать, так это передать NSManagedObjects между потоками. Вы можете сказать своему контексту в основном потоке, чтобы сохранить, выполнив [mainContext performBlock:^{ NSError *error = nil; [mainContext save:&error]; }; из другого потока. - person Fábio Oliveira; 15.04.2013
comment
Я всегда получаю доступ к основным объектам данных из собственного потока. Следовательно, я очень редко использую PerformBlock или PerformBlockAndWait. Вещи работают нормально. - person user4234; 16.04.2013
comment
@FábioOliveira Нет, Apple очень четко говорит об этом: вы не можете получить к ним доступ через потоки. PerformBlock позволяет вам попросить один поток попросить другой поток выполнить код для него. Компилятор позволит вам получить простой доступ, но если вы это сделаете, то рано или поздно вы гарантированно получите ошибку согласованности во время выполнения (то есть: поврежденная база данных CoreData, и все вырвется на свободу. Был там, видел это) - person Adam; 08.08.2013
comment
@ Адам, ты прав. Apple указывает это в developer.apple. com/library/mac/documentation/Cocoa/Reference/: PerformBlock: и PerformBlockAndWait: убедитесь, что операции блока выполняются в очереди, указанной для контекста. Метод PerformBlock: немедленно возвращается, и контекст выполняет методы блока в своем собственном потоке. При использовании метода PerformBlockAndWait: контекст по-прежнему выполняет методы блока в своем собственном потоке, но метод не возвращается до тех пор, пока блок не будет выполнен. - person Fábio Oliveira; 09.08.2013
comment
Насколько я понимаю, PerformBlockAndWait работает в потоке вызывающего абонента, в отличие от PerformBlock. - person Brad Thomas; 25.11.2013
comment
@BradThomas performBlockAndWait: запускается в потоке контекста, как и performBlock:, но заставляет поток вызывающего абонента ждать завершения выполнения блока. - person tonytony; 06.12.2013
comment
@tonytony Я хотел бы, чтобы это прояснилось, поэтому я бросаю вам вызов… то, что вы говорите, не соответствует убедительному ответу (и убедительному вопросу), опубликованному в этой теме… stackoverflow.com/questions/11831946/ - person Brad Thomas; 06.12.2013
comment
@BradThomas Я попробовал po [NSThread currentThread] в отладчике внутри и снаружи вызова performBlockAndWait: и... О, это действительно выполняется в потоке вызывающего. Спасибо за ссылку. - person tonytony; 08.12.2013