Как использовать Magical Record для создания и обновления объектов и их сохранения без использования contextForCurrentThread

Я только что прочитал запись автора MagicalRecord в блоге о Почему contextForCurrentThread не работать в MagicalRecord.

contextForCurrentThread устарел, и вместо него следует использовать saveWithBlock, поскольку он создает безопасный новый NSManagedObjectContext для соответствующего потока.

До сих пор я широко использовал contextForCurrentThread в своем приложении. Однако у меня возникли проблемы с выяснением того, как использовать вместо этого saveWithBlock, так как моя выборка и сохранение не обязательно происходят последовательно.

В настоящее время я делаю такие вещи, как:

localContext = NSManagedObjectContext.MR_contextForCurrentThread
person = Person.MR_createInContext(localContext)
person.name = "John Smith"

Затем пользователь может перемещаться по приложению, отображать различные контроллеры, представления и т. д. Другие объекты могут быть созданы с использованием метода, аналогичного приведенному выше коду.

Затем в какой-то произвольный момент в будущем, когда пользователь решит сохранить, я запускаю этот метод:

localContext = NSManagedObjectContext.MR_contextForCurrentThread
localContext.MR_saveToPersistentStoreWithCompletion(
  lambda { |success, error|
    # ...
  }
)

Каков рекомендуемый способ создания и обновления объектов, а затем их сохранения без использования contextForCurrentThread?


person Paul Sturgess    schedule 08.10.2013    source источник
comment
Вы управляете своими потоками вручную? Вы уверены, что person = Person.MR_createInContext(localContext) и localContext.MR_saveToPersistentStoreWithCompletion выполняются в одном потоке?   -  person Arek Holko    schedule 08.10.2013
comment
Или, может быть, обе части вашего кода выполняются в основном потоке? (это бы сильно упростило задачу)   -  person Arek Holko    schedule 08.10.2013
comment
Там, где я использую разные потоки, я вызываю NSManagedObjectContext.MR_contextForCurrentThread.MR_saveToPersistentStoreAndWait.   -  person Paul Sturgess    schedule 08.10.2013
comment
Значит, вы не уверены, что контекст, в котором вы создаете Person, будет таким же, как и контекст, в котором вы выполняете MR_saveToPersistentStoreWithCompletion?   -  person Arek Holko    schedule 08.10.2013


Ответы (3)


Итак, я использую объект C, а не RubyMotion, но вы должны уметь делать такие вещи:

MagicalRecord.saveWithBlock(
   lambda { |localContext|
       person = Person.MR_createInContext(localContext)
       #update person stuff here
   }
)

ИЗМЕНИТЬ

Если вы хотите сохранить контекст позже, вам просто нужно удерживать его:

// Somewhere in your ViewController, etc
NSManagedObjectContext *context = [NSManagedObjectContext MR_confinementContext];


// Somewhere else
Person *p = [Person MR_createInContext:context];

// And in yet another method
[context MR_saveToPersistentStoreAndWait];

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

[context MR_saveToPersistentStoreCompletion:^(BOOL success, NSError *error){
   //called on the main thread when save is complete
}];
person casademora    schedule 08.10.2013
comment
Разве это не создание и сохранение всего за один раз? Могу ли я не создавать объект Person, а затем сохранять его в другой момент в будущем? - person Paul Sturgess; 08.10.2013
comment
MR_confinementContext недоступен в версии 2.2 MagicalRecord. Какую ветку на Github вы бы порекомендовали? - person Paul Sturgess; 09.10.2013
comment
Мне удалось заставить это работать в версии 3 MagicalRecord, используя MagicalRecord.saveWithBlock для фоновых потоков. В то время как в основном потоке используется: MagicalRecordStack.defaultStack.context. - person Paul Sturgess; 10.10.2013
comment
Просто примечание, чтобы сказать, что в ответе метод MR_saveToPersistentStoreCompletion должен быть MR_saveToPersistentStoreWithCompletion - person Paul Sturgess; 15.01.2014

вот учебник для нового API: http://ablfx.com/blog/article/2 вот ссылка: http://cocoadocs.org/docsets/MagicalRecord/2.1/

  1. в этом

    [MagicalRecord setupCoreDataStackWithStoreNamed:@"MyDatabase.sqlite"];

  2. расторгать

    [MagicalRecord cleanUp];

  3. вставлять

    Person *alex = [Person MR_createEntity]; alex.name = @"Alex"; alex.age = @23;

  4. Выбрать

    /Получить все для подкласса NSManagedObject NSArray *people = [Person MR_findAll];

    // Получить первую запись Person *aPerson = [Person MR_findFirst];

    //Условное получение записей и сортировка NSArray *people = [Person MR_findByAttribute:@"name" withValue:@"alex" andOrderBy:@"age" ascending:YES];

  5. Обновить

    // Обновить полученный объект так же просто, как манипулировать его свойствами aPerson.age = @56;

  6. удалять

    //Удалить все записи [Person MR_truncateAll];

    //Удалить одну запись после ее получения [alex MR_deleteEntity];

  7. спасти

    //Для любых сущностей, которые будут фактически сохранены/обновлены/удалены на диске, вызовите следующий метод [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];

    // Снова проверьте репозиторий MagicalRecord для дополнительных вариантов сохранения

person lbsweek    schedule 11.01.2014

Возможно, я ошибаюсь, но мне кажется, что Magical Record не подходит для такого варианта использования. Вот как бы я сделал то, что вы хотите, в чистом Core Data:

  1. Создайте независимый или вложенный контекст и сохраните где-нибудь (AppDelegate, одноэлементный объект и т. д.) ссылку на него.
  2. Выполняйте вставки, чтения, обновления и удаления с помощью performBlock: и performBlockAndWait:
  3. Сохраните контекст с помощью:

    [context performBlock:^{
        ZAssert([context save:&error], @"Save failed: %@\n%@", [error localizedDescription], [error userInfo]);
    }];
    

Это, кажется, стандартный подход к такого рода проблемам. Это хорошо описано в Интернете, например. Общие базовые практики — основные данные в фоновом режиме.

person Arek Holko    schedule 08.10.2013
comment
MagicalRecord наверняка легко справится с этим случаем. См. stackoverflow.com/a/19251873/5619. Вы также должны держаться подальше от синглтонов данных, так как это будет легко реализовать сейчас, но позже вызовет сумасшедшие проблемы. - person casademora; 08.10.2013
comment
О, я не знал о некоторых недавних изменениях в MagicalRecord. В своем ответе вы написали The main idea here is that you just need to hold on to the context and perform, так где бы вы сохранили этот контекст, предполагая, что пользователь посещает пару разных контроллеров представления? Вы бы передали его между венчурными капиталистами? - person Arek Holko; 08.10.2013
comment
Вы можете создать новый для каждого нового контекста. MagicalRecord может помочь вам объединить изменения между контекстами, не перегружая вашего делегата приложения (что приводит к еще большей боли). - person casademora; 09.10.2013
comment
Я спрашивал в контексте (каламбур не предназначен :)) исходного вопроса. Предположим, это выглядит следующим образом: создается новый контекст, в него вносятся какие-то изменения; затем пользователь перемещается между разными контроллерами представления; в какой-то момент времени пользователь хочет сохранить изменения в контексте (он может находиться в другой ВК, чем та, в которой был создан контекст). Такая настройка позволяет нам не сохранять изменения в текущем контексте в постоянном хранилище, например. когда пользователь отменяет в какой-то момент. - person Arek Holko; 09.10.2013