Подтвердить что ты не робот

Предварительная загрузка базы данных данных ядра в iOS 5 с UIManagedDocument

Я пытаюсь придумать способ предварительной загрузки данных в основные данные при использовании UIManagedDocument. Моя попытка до сих пор заключается в том, чтобы сделать документ в приложении "Loader", используя этот код.

NSURL *url  = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                      inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:@"Default Database"];
if(![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]]){
    [self.document saveToURL:self.document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
        if(success)[self loadDataIntoDocument];
    }];
}

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

Моя проблема в том, что я не могу понять, как скопировать этот документ из пакета приложений и успешно использовать его в качестве документа.

Я попытался скопировать каталог документов как есть из пакета приложений и попытаться получить к нему доступ в качестве документа, который дал ошибку, что UIManagedDocument может получить доступ только к пакету файлов. Я попытался создать еще один свежий документ в главном приложении и скопировать файл persistentStore из пакета, который был создан в документе с той же ошибкой. И я пробовал использовать метод UIManagedDocument -(BOOL)loadFromContents:ofType:error:. Я даже не уверен, что это то, что я должен использовать.

Есть ли у кого-нибудь идеи относительно того, как это обычно делается? Благодарю!

4b9b3361

Ответ 1

Я не думаю, что вам нужно возиться с файлами и каталогами в iOS.

Однако вы можете открыть документ непосредственно из своего пакета. Для этого вам просто нужно скопировать весь каталог документов, созданный в приложении Loader, в ваш последний пакет. Структура должна быть довольно простой, всего две директории с файлом persistentStore внутри.

Затем, когда вы хотите открыть документ, вам нужно позаботиться о двух вещах: вам нужно использовать каталог пакетов в качестве базового каталога, и вам нужно добавить / в конец "файла", name, поэтому UIManagedDocument знает, что каталог является документом. Код выглядит следующим образом:

NSURL* url = [[NSBundle mainBundle] bundleURL];
url = [url URLByAppendingPathComponent:@"filename/"];
UIManagedDocument* doc = [[UIManagedDocument alloc] initWithFileURL:url];

Обратите внимание, что вы не можете писать в этот файл, так как вам не разрешено писать внутри вашего пакета приложений. Поэтому, если вы хотите иметь документ, доступный для записи, вам необходимо скопировать этот документ в папку документов. Вы можете сделать это легко, просто сохранив doc в другом месте:

[doc saveToURL:newURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){}]

Еще одна вещь: вы должны убедиться, что структура папок создана в вашем приложении. Самый простой способ сделать это - перетащить всю папку в ваш проект, а затем выбрать "Создать ссылки на папки для любых добавленных папок". Для "файла" symbollist_en (который фактически является самой папкой/папкой) он должен выглядеть следующим образом:
A folder reference in XCode
Если вы этого не сделаете, "содержимое" документа будет находиться непосредственно в вашем приложении, которое невозможно открыть как UIManagedDocument, как вы выяснили.

Ответ 2

Ответ Shezi много помог, но как и другие: Предварительно загруженная база данных основных данных в ios5 с UIManagedDocument и здесь: Предварительная загрузка базы данных данных ядра вверх с помощью UIManagedDocument У меня были проблемы.

Во-первых, поведение на тренажере заметно отличается от поведения на устройстве. Если вы создаете экземпляр UIManagedDocument с помощью initWithURL, где URL-адрес указывает на пакет приложений, вы получите предупреждение о том, что это каталог только для чтения в консоли при работе на устройстве, но на этом симуляторе не появляется такое предупреждение. Обработка разрешений, похоже, совсем другая, и вы можете получить разные результаты.

В документах указано, что migratePersistentStore:toURL:options:withType:error: следует использовать вместо [doc saveToURL:newURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){}]

Я потратил много времени, пытаясь заставить это работать, но с большим трудом получил указатель на постоянный магазин. Несмотря на то, что мое приложение отлично работало для операций только для чтения после решения Shezi, постоянный координатор хранилища продолжал давать мне нулевой указатель для постоянного хранилища. Это произошло, когда я попробовал как – persistentStores (который возвращал пустой массив), так и – persistentStoreForURL: Если кто-нибудь сможет объяснить, почему это произошло, мне было бы интересно. Досадно было, что он иногда работал на симуляторе, но когда я протестировал его на устройстве, он потерпел неудачу.

В конце концов, я все изменил и скопировал папку пакета в каталог документов, прежде чем создавать экземпляр UIManagedDocument. Кажется, это трюк. Вот код. Предполагается, что ваш UIManagedDocument является свойством класса. Я поместил это в метод viewWillAppear исходного контроллера представления. Помните, что вам нужно открыть документ, если вы создаете экземпляр URL, содержащего существующее постоянное хранилище.

if (!self.yourUIManagedDocument) {
    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"yourUIManagedDocument"];
    NSString *documentsFolderPath = [documentsDirectory stringByAppendingPathComponent:@"yourUIManagedDocument"];

    NSURL *documentsUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    documentsUrl = [documentsUrl URLByAppendingPathComponent:@"yourUIManagedDocument"];

    if (![[NSFileManager defaultManager] fileExistsAtPath:documentsFolderPath]) {
        NSError *error = nil;

        if([[NSFileManager defaultManager] copyItemAtPath:bundlePath
                                                   toPath:documentsFolderPath
                                                    error:&error]) {
            self.yourUIManagedDocument = [[UIManagedDocument alloc] initWithFileURL:documentsUrl];
            [self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
            }];
        } else {
            NSLog(@"%@", error);
        }
    } else {
        self.yourUIManagedDocument = [[UIManagedDocument alloc] initWithFileURL:documentsUrl];
        [self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
        }];
    }
} else if (self.yourUIManagedDocument.documentState == UIDocumentStateClosed) {
    //Document is closed. Need to open it
    [self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
    }];
}

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

Ответ 3

Метод shezi, похоже, работает для меня, единственное, что я хотел бы добавить, это "файл" означает symbolist_en в этом случае. Это может быть немного запутанным для новых разработчиков, таких как я (я помещал persistentStore/).

Ответ 4

Ответ Шези очень помог. Но это не сработало. Я удалил каталог документов в xcode, но не был скопирован из пакета в каталог Documents. Затем я наткнулся на macbeb question относительно предварительной загрузки. Я пробовал его подход, который включал в себя только файл persistentStore в комплекте. Затем создайте требуемый каталог имен документов в папке "Документ" и затем скопируйте файл persistentStore на этот путь.

Проверьте код с комментарием "COPY FROM BUNDLE"

Я использовал статический класс для обработки документов.

+(DocumentHandler *) sharedDocumentHandler {
    static DocumentHandler *mySharedDocumentHandler = nil;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        mySharedDocumentHandler = [[self alloc] init];
    });
    return mySharedDocumentHandler;
}

- (id)init {
    self = [super init];
    if (self) {
        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        url = [url URLByAppendingPathComponent:@"YourDocumentName"];
        self.sharedDocument = [[MyUIManagedDocument alloc] initWithFileURL:url];
    }
    return self;
}
- (void)performWithDocument:(OnDocumentReady)onDocumentReady
{
    void (^OnDocumentDidLoad)(BOOL) = ^(BOOL success) {
        if(success) {
            onDocumentReady(self.sharedDocument);
        } else {
            NSLog(@"Error occured while creating or opening the database");
        }
    };

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.sharedDocument.fileURL path]]) {
        NSError *error = nil;

        // COPY FROM BUNDLE

        NSFileManager *fileManager = [NSFileManager defaultManager];

        NSString *DB = [[self.sharedDocument.fileURL path] stringByAppendingPathComponent:@"StoreContent"];

        [fileManager createDirectoryAtPath:DB withIntermediateDirectories:YES attributes:nil error:&error];

        NSLog(@"create directory error: %@",error);

        DB = [DB stringByAppendingPathComponent:@"persistentStore"];

        NSString *shippedDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"persistentStore"];

        NSLog(@"%d",[fileManager fileExistsAtPath:shippedDB]);

        [fileManager copyItemAtPath:shippedDB toPath:DB error:&error];

        NSLog(@"Copy error %@",error);        
    }

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.sharedDocument.fileURL path]]) {
        //Create documents [This is required while creating database first time]
        [self.sharedDocument saveToURL:self.sharedDocument.fileURL
                forSaveOperation:UIDocumentSaveForCreating
               completionHandler:OnDocumentDidLoad];
    } else if (self.sharedDocument.documentState == UIDocumentStateClosed) {
        [self.sharedDocument openWithCompletionHandler:OnDocumentDidLoad];
    } else if (self.sharedDocument.documentState == UIDocumentStateNormal) {
        OnDocumentDidLoad(YES);
    }
}