4

I have a subclass of UIDocument called Song that I use for storing users' content locally. The main reason I'm using UIDocument is for the autosaving feature.

I have an issue where after autosaving a document, -[Song revertToContentsOfURL:] is called. This causes the document to load from disk again. The data is up-to-date, but other properties get reset as my app thinks that I am opening a new document. I could use a flag to check if the document is already open and not reset the relevant properties, but I would rather prevent revertToContentsOfURL: from being called in the first place.

Note: this doesn't always happen. It seems that when a new document is created on the first launch of the app, it will call revertToContentsOfURL: after each autosave, but on subsequent runs the autosave performs as expected. This could just be a coincidence though.

Here is the relevant code:

Song.h

typedef NS_OPTIONS(NSUInteger, ChangeFlag) {
    ChangeFlagNone        = 0,

    ChangeFlagPaths       = 1 << 0,
    ChangeFlagInstruments = 1 << 1,
    ChangeFlagColors      = 1 << 2,
    ChangeFlagProperites  = 1 << 3,
    ChangeFlagMixer       = 1 << 4,
    ChangeFlagTools       = 1 << 5,
    ChangeFlagScreenshot  = 1 << 6,

    ChangeFlagAll = ~ChangeFlagNone
};

@interface Song : UIDocument

@property (nonatomic) ChangeFlag changes;

- (void)addChange:(ChangeFlag)change;
- (void)removeChange:(ChangeFlag)change;

@end

Song.m

#import "Song.h"

@implementation Song

- (void)addChange:(ChangeFlag)change {
    self.changes |= change;
}

- (void)removeChange:(ChangeFlag)change {
    self.changes &= ~change;
}

- (void)setChanges:(ChangeFlag)changes
{
    _changes = changes;

    dispatch_async(dispatch_get_main_queue(), ^{
        if (_changes == ChangeFlagNone) {
            [self updateChangeCount:UIDocumentChangeCleared];
        } else {
            [self updateChangeCount:UIDocumentChangeDone];
        }
    });
}

- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
    // populate various app properties
    // -[Song addChange:] will be called multiple times
    // ...

    // clear changes (called directly instead of through setChange to avoid async)
    _changes = ChangeFlagNone;
    [self updateChangeCount:UIDocumentChangeCleared];

    return YES;
}

- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
    NSFileWrapper *rootDirectory = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];

    // store current changes value before clearing
    ChangeFlag changes = _changes;

    // clear changes (called directly instead of through setChange to avoid async)
    _changes = ChangeFlagNone;
    [self updateChangeCount:UIDocumentChangeCleared];

    // update various file wrappers in rootDirectory, based on flags in `changes` variable
    // ...

    return self.rootDirectory;
}

@end
Jayson
  • 1,689
  • 14
  • 26
  • Did you figure this one out? revertToContentsOfURL: can be called when the document changes via iCloud. – Taylor Oct 24 '16 at 23:41
  • @Taylor I'm not using iCloud. I never did figure it out completely but I think it had something to do with me directly reading a file inside the UIDocument without opening the document – Jayson Oct 25 '16 at 01:49

0 Answers0