0

UIManagedDocument を使用してアプリを動作させることを扱っています。数日前に別の質問を投稿しましたが、まだ機能していません。これをもっとうまくできるか見てみましょう。
私のアプリは、plist ファイルからいくつかのデータをロードし、それをデータベースに入力する必要があります。次に、時々変更されるいくつかのパラメーターがあり、それらをデータベースにロードして更新する必要もあります。
アプリは次の順序に従う必要があります: データベースを作成/開き、データをロードし、変数データを更新します。
私の問題は、そのシーケンスを正しくたどろうとしたときに発生します。これは主に、すべてのオブジェクトがデータベースに作成される前に変数データを更新できない (したがって、更新する必要がある nil 変数) ためであり、私の回避策は予期しない結果につながるだけです。クラッシュと非論理的な行動。
ここ'

ビューコードでは:

- (void)viewDidLoad{
    [super viewDidLoad];
    self.database = [DataHelper opendatabaseAndUseBlock:^{
        [self setupFetchedResultsController]; // I pass this method trough a Block because I want it
                                              // to be executed once the database is opened, not before.
    }];
}  

次に、次のコードを含むこのヘルパー クラス「DataHelper」を使用します。

@implementation DataHelper

// This method creates and opens the database, then calls the necessary methods
+ (UIManagedDocument *)openDatabaseAndUseBlock:(completion_block_t)completionBlock
{

    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    url = [url URLByAppendingPathComponent:@"Database"];
    UIManagedDocument *database = [[UIManagedDocument alloc] initWithFileURL:url];

    if (![[NSFileManager defaultManager] fileExistsAtPath:[database.fileURL path]]) {
        [database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            [self loadDataIntodatabase:database withSuccess:success];
            completionBlock();
        }];

    } else if (database.documentState == UIDocumentStateClosed) {
        [database openWithCompletionHandler:^(BOOL success) {
            [self loadDataIntodatabase:database withSuccess:success];
            completionBlock();
        }];

    } else if (database.documentState == UIDocumentStateNormal) {
        [self loadDataIntodatabase:database withSuccess:YES];
        completionBlock();
    }

    return database;
}


// This method loads the "static" data into the database, by reading it from a plist file.
// Once the loading finishes, it should call the last method, for updating the variable data
+ (void)loadDataIntoDatabase:(UIManagedDocument *)database withSuccess:(BOOL)success
{
    if (success) {        
        NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"];
        NSArray *plistData = [NSArray arrayWithContentsOfFile:path];

        [database.managedObjectContext performBlock:^{
            for (NSDictionary *data in plistData) {
                [Object createObjectWithData:data inManagedObjectContext:database.managedObjectContext];
            }

            // Not sure what to do here!!
            //[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
                 // [DataHelper updateVariableDataOfDatabase:database];
            //}];

            // Or...?
            //[database updateChangeCount:UIDocumentChangeDone];             
            // [DataHelper updateVariableDataOfDatabase:database];

        }];

    } else {
        NSLog(@"NO SUCCESS");
    }
}

// This last method updates some parameters of the existing data
// in the database, to the ones found in another plist file
+ (void)updateVariableDataOfDatabase:(UIManagedDocument *)database
{
    // This path is provisional, should be gotten from an online resource
    NSString *path = [[NSBundle mainBundle] pathForResource:@"VariableData" ofType:@"plist"];
    NSDictionary *variables = [NSDictionary dictionaryWithContentsOfFile:path];

    [database.managedObjectContext performBlock:^{
        // Update the objects changing the values of the variable parameters
        // to the ones found in "variables"

        // Now I should save the changes, or maybe not?
        //[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];
        // Or...
        //[database updateChangeCount:UIDocumentChangeDone];

    }];
}
@end

「saveToURL」メソッドを使用すると、正しくないように見えますが、すべてのデータがデータベースにロードされるまで最後のメソッドが実行されないため、ロード シーケンスが正しく実行されます。ただし、多くの操作を実行しようとすると、アプリがランダムにクラッシュします (削除、更新、再読み込みなど、多くの節約が行われます)。
一方、「updateChangeCount」を使用すると、アプリはクラッシュしなくなりますが、シーケンスはうまく機能しません。変数データは更新されず、アプリはそこにあるオブジェクトを見つけられません。データベースなど。各アクションの間に2分ほど待つと、はい、機能します...しかし、それは私が望んでいることではありません.

ここで助けていただければ幸いです。これは私の時間を浪費しており、このプロジェクトの締め切りはかなり間近です :( どうも
ありがとうございました!

4

1 に答える 1

0

しばらく経ちましたが、ここで問題が解決されていることを願っていますが、念のため、過去2か月間、UIManagedDocument関連の問題の山を自分で解決してきたので、苦痛を感じます。ここで行っていることは、最近のプロジェクトで必要だったこととかなり似ています。

残念ながら、UIManagedDocumentを保存する(または保存しない)方法に関するドキュメントやさまざまな提案がオンライン上に浮かんでいるようです。saveToURLアプローチとupdateChangeCountアプローチの両方を使用して同様の結果が見つかりましたが、updateChangeCountアプローチでは保存エラーが発生する頻度は低いようです。しかし、それがあなたの問題に実際に影響を与えているとは思いません。

ドキュメントにアクセスするスレッドが1つしかない限り、データ用に開いているドキュメントが1つしかない限り、実際に保存する必要はありません。そのコンテキスト内で自動的に保存されます。変更をそのコンテキストから他のコンテキスト(UIManagedDocumentには2つあります)にプッシュし、最終的にクラウドや他のデバイスにプッシュするには、保存が必要です。完了ハンドラー内にperformBlockの2つのレイヤーがあり、これが複雑になり、複数のスレッドが同時にデータベースに予測できない順序でアクセスする可能性があります。すべてのプリロードと設定を行うと、completionHandler内で順番に実行され、その後にopendatabaseAndUseBlockに相当するものが続き、クラッシュすることはありません。

于 2012-06-13T18:06:15.673 に答える