Сохранение NSOperationQueue

Кто-нибудь знает, как перенести NSOperationQueue на диск между запусками приложений?

Ответ 1

Нет никакого способа сделать это. NSOperations - это действия, части исполняемого кода, которые невозможно полностью сохранить на диске.

Однако в вашем приложении вы должны знать, какие операции вы добавили в очередь. Либо использование подкласса, либо наличие некоторых метаданных. Затем вы сохранили метаданные, информацию о том, что должно быть сделано, по-своему. При запуске приложения действия, которые ранее находились в очереди, теперь могут быть восстановлены из загруженных метаданных.

Вряд ли что-нибудь еще я могу вам дать, но я надеюсь, что это уже было полезно!

Ответ 2

Очень просто, сначала убедитесь, что все ваши NSOperations принимают протокол NSCoding и реализуют методы, чтобы указать, какие поля они хотят сохранить и восстановить:

MyOperation.h

@interface MyOperation : NSOperation<NSCoding>

MyOperation.m

#pragma mark NSCoding

#define kSomeKey       @"someKey"

- (void) encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:[self someKey] forKey:kSomeKey];
}

- (id)initWithCoder:(NSCoder *)decoder {

    if (self = [super init]) {
        NSString *someKey = [decoder decodeObjectForKey:kSomeKey];
        [self setSomeKey:someKey];
    }

    return self;
}

Наконец, сериализуйте и десериализуйте свою очередь, когда захотите. Это сохранит его в хранилище на телефоне в файле Documents/data, предполагая, что ваша очередь называется operations.

NSString * const dataPath = @"~/Documents/data";

// private
- (void) serializeQueue {
    NSArray* storedOperations = [[self operations] operations];

    [NSKeyedArchiver archiveRootObject:storedOperations toFile:[dataPath stringByExpandingTildeInPath]];
}

// private 
- (void) deserializeQueue {
    NSArray* storedOperations = [NSKeyedUnarchiver unarchiveObjectWithFile:[dataPath stringByExpandingTildeInPath]];

    NSLog(@"count of opeations: %lu", (unsigned long) [storedOperations count]);
}

Ответ 3

Я согласен с Максом - не существует общего способа сделать это. Обычно вы хотите сделать операции концептуально транзакционными и связанными с состояниями в конечной машине. Сохраняйте текущее состояние и любые другие соответствующие данные по каждому переходу состояния (то есть завершенную операцию), затем располагайте единый код, который заполняет NSOperationQueue соответствующими операциями, основанными на текущем состоянии. Вызовите этот же код из вашего UI-управляемого кода и перезапустите приложение.

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

Ответ 4

Если у вас относительно простая очередь, без зависимостей между операциями, это должно быть довольно просто сделать, используя NSCoder.

Общий подход для этого заключается в следующем:

  • Итерировать через ожидающие элементы NSOperation в очереди, используя свойство NSOperationQueue . Операции будут в том порядке, в котором они были добавлены в очередь, и вы захотите сохранить порядок.

  • Ваши NSOperations должны быть подклассифицированы и внедрены протокол NSCoding, так что каждая операция знает, как архивировать и разблокировать себя, используя NSArchiver. Вам будет необходимо определить, какие свойства нужно сериализовать, чтобы правильно восстановить состояние очереди. Если вы создали какие-либо межоперационные зависимости, ваша ответственность - как-то сохранить и восстановить эти отношения - и, по всей вероятности, если ваша очередь сложна таким образом, вы, возможно, не захотите это делать в первую очередь. Сериализуйте (архивируйте) операцию и сохраните ее в NSArray или используйте какую-либо другую структуру для сохранения порядка очередей.

  • Архивируйте NSArray, содержащий сериализованные операции, в файл.

  • Чтобы восстановить свою очередь, вы "распакуете" NSArray из файла, а затем перебираете список операций, сворачиваете каждый NSOperation и добавляете его в очередь относительно исходного заказа.