Предварительная загрузка основной базы данных в iOS 5 с UIManagedDocument - PullRequest
13 голосов
/ 31 декабря 2011

Я пытаюсь найти способ, которым я могу предварительно загружать данные в базовые данные, используя UIManagedDocument.Пока что я пытаюсь создать документ в приложении «Загрузчик» с помощью этого кода ..

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: метод. Я даже не уверен, что это то, что я должен использовать.

У кого-нибудь есть идеи относительно того, как это обычно делается?Спасибо!

Ответы [ 4 ]

9 голосов
/ 14 января 2012

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

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

Впоследствии, когда вы хотите открыть свой документ, вам нужно позаботиться о двух вещах: вам нужно использовать каталог bundle в качествебазовый каталог, и вам нужно добавить / в конце имени файла, чтобы 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, как вы узнали.

4 голосов
/ 30 июля 2012

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

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

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

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

В конце концов, я все изменил и сначала скопировал папку bundle в каталог документов, а затемсоздание экземпляра 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) {
    }];
}

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

0 голосов
/ 14 марта 2013

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

Проверьте код с комментарием «КОПИЯ ИЗ ПАКЕТА»

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

+(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);
    }
}  
0 голосов
/ 20 ноября 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...