0

シンプルな UIManagedDocument ベースの Core Data アプリがあります。私はiOSでプログラミングするのが初めてで、ほとんど着手できず、立ち往生しています。Core Data に格納されている People NSManagedObjects があります。アプリを最初に起動したとき、エントリはありませんが、モーダル VC を上にスライドして閉じると、魔法のように表示されます。私のデザインは、iTunes U/Sanford コースの「Photomania」アプリに大まかに基づいていますが、managedObjectContext の取得を処理するシングルトン CoreDataStore オブジェクトを使用しています。これは私の CoreDataStore のコードです:

+ (CoreDataStore *)sharedStore
{
    static CoreDataStore *sharedStore = nil;
    if (!sharedStore)
        sharedStore = [[super allocWithZone:nil] init];

    return sharedStore;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [self sharedStore];
}

- (NSManagedObjectContext *)getContext
{
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                         inDomains:NSUserDomainMask] lastObject];
    url = [url URLByAppendingPathComponent:@"dbDocument"];
    UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];

    if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
        NSLog(@"No file exists...");
        [document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            NSLog(@"Document saveForCreating completionHandler invoked. Success: %hhd", success);
            if (success) {
                self.managedObjectContext = document.managedObjectContext;
                NSLog(@"Got context for created file!!");
            }
        }];
    } else if (document.documentState == UIDocumentStateClosed) {
        NSLog(@"Document state is closed. documentState == %u", document.documentState);
        [document openWithCompletionHandler:^(BOOL success) {
            NSLog(@"Document opening success: %hhd", success);
            if (success) {
                self.managedObjectContext = document.managedObjectContext;
                NSLog(@"Got context for now-opened file!!");
            }
        }];
    } else {
        self.managedObjectContext = document.managedObjectContext;
        NSLog(@"Got context for already-opened file!!");
    }

    return self.managedObjectContext;
}

PeopleListViewController のコードは次のとおりです。

- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
    _managedObjectContext = managedObjectContext;
    if (managedObjectContext) {
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
        request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name"
                                        ascending:YES
                                        selector:@selector(localizedCaseInsensitiveCompare:)]];
        request.predicate = nil;  // all Persons
        self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    } else {
        self.fetchedResultsController = nil;
    }
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if (!self.managedObjectContext)
        [self setManagedObjectContext:[[CoreDataStore sharedStore] getContext]];
}

これは、起動直後の結果です。

打ち上げ後

これはモーダル VC です。

モーダルVC

これは、モーダル VC を閉じた後です ([キャンセル] をタップ):

モーダル後

私は managedObjectContext で performFetch を使用しようとしましたが、Core Data ドキュメントが開かれたと報告された後もそれを遅らせました。何も機能しません。どんな助けでも大歓迎です。

4

2 に答える 2

0

NSFetchedResultsControllerあなたのtableViewを魔法のように更新しません。CoreDataViewController のようなアシスタント クラスがほとんどないため、Photomania は少し複雑であることがわかりました。したがって、メソッドを呼び出すreloadDataか、ペアを使用することによってのみ、tableVew を再ロードできます。また、メソッドを呼び出すことによってのみ更新される場合があります。私は通常ゲッターを使用します:beginUpdatesendUpdatesNSFetchedResultsControllerperformFetch:NSManagedObjectContext

- (NSFetchedResultsController*)fetchedResultsController
{
    if (!_fetchedResultsController)
    {
        NSFetchRequest* fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"some entity name"];
        fetchRequest.predicate = [NSPredicate predicateWithFormat:@"some predicate"];
        fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:@"name" cacheName:nil];
        _fetchedResultsController.delegate = self;
        NSError* error;
        [_fetchedResultsController performFetch:&error];
        if (error)
        {
            NSLog(@"Fetch ERROR. %@", error);
        }
    }
    return _fetchedResultsController;
}

ここで私は自分自身に設定NSFetechedResultsControllerDelegateしました。そしてperformFetch:、データを取得します。そして、デリゲートのメソッドを実現します:

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller
{
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController*)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                          withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                          withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath*)newIndexPath
{
    UITableView *tableView = self.tableView;

    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
                    atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller
{
    [self.tableView endUpdates];
}
于 2013-10-16T02:54:05.680 に答える
0

コードをざっと見ただけで、コンテキストを非同期的に作成していることに気付きました。これは素晴らしいことですが、そのコンテキストの準備ができたら、テーブル ビュー コントローラーに通知し、reloadData を呼び出す必要があります。

データ ストアの完了ハンドラーは、テーブル ビュー コントローラーでコンテキスト プロパティを設定する必要があります。

于 2013-10-16T02:50:56.003 に答える