2017-06-14 53 views
0

私のiosアプリケーションのバックグラウンドでコアデータを更新しようとしていますが、まずコアデータを削除してから追加します。しかし、いくつかの関数を実行するには特定のセグが必要ですが、バックグラウンドですべてを実行しようとすると、ページを変更して元に戻さない限り、これらの関数は決して実行されません。viewWillAppear()を手動で呼び出すときのiosエラー(Objective-C)

私は手動でviewWillAppear()を呼び出してこのエラーを修正しようとしましたが、次のエラーが発生します。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x17191c00 of class CardScanView was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x16d99c30> (
<NSKeyValueObservance 0x16dcdf20: Observer: 0x17191c00, Key path: verifyingCard, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x16d5db30> 

エラーが発生したクラスのメソッド:

- (void) resetDatabase { 
    count++; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 
     ConDAO *con = [[ConDAO alloc] init]; 
     DatabaseManager *manager = [DatabaseManager sharedManager]; 
     NSError * error; 
     NSURL * storeURL = [[[manager managedObjectContext] persistentStoreCoordinator] URLForPersistentStore:[[[[manager managedObjectContext] persistentStoreCoordinator] persistentStores] lastObject]]; 
     [[manager managedObjectContext] reset];//to drop pending changes 
     if ([[[manager managedObjectContext] persistentStoreCoordinator] removePersistentStore:[[[[manager managedObjectContext] persistentStoreCoordinator] persistentStores] lastObject] error:&error]) 
     { 
      // remove the file containing the data 
      [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]; 
      //recreate the store like in the appDelegate method 
      [[[manager managedObjectContext] persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store 
     } 
     NSLog(@"*****************************"); 
     NSLog(@"updating"); 
     NSLog(@"count: %d", count); 
     NSLog(@"*****************************"); 

     [self populateDatabase:0 con:con]; 


     NSTimer *timer = [NSTimer timerWithTimeInterval:60.0 
               target:self 
               selector:@selector(resetDatabase) 
               userInfo:nil repeats:NO]; 
     [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 
     dispatch_async(dispatch_get_main_queue(), ^(void){ 
      CardScanView *card = [[CardScanView alloc] init]; 

      [[NSNotificationCenter defaultCenter] addObserver:card 
                selector:@selector(viewWillAppear:) 
                 name:@"updated" object:nil]; 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"updated" object:nil]; 

       }); 
     }); 
} 

viewWillAppearとviewDidDissapear他のクラス:

- (void)viewWillAppear:(BOOL)animated{ 
    [super viewWillAppear:animated]; 
    // Setup KVO for verifyingcard 
    [self addObserver:self forKeyPath:@"verifyingCard" options:NSKeyValueObservingOptionNew context:nil]; 

    if([BluetoothTech isEqualToString:@"BLE"]){ 
     self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey: @YES}]; 
    } 
    else if([BluetoothTech isEqualToString:@"HID"]){ 
     [self.bluetoothScanTextView becomeFirstResponder]; 
    } 
    [self loadStudents]; 
} 


- (void)viewDidDisappear:(BOOL)animated{ 
    [super viewDidDisappear:animated]; 
    // Disconnect the bluetooth peripheral device if it exists 
    if(self.discoveredPeripheral != nil){ 
     [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; 
    } 
    // Remove KVO for verifyingCard 
    [self removeObserver:self forKeyPath:@"verifyingCard"]; 
} 

エラーの原因といただきました、にもむしろこれにアプローチするより良い方法があります手動でviewDidLoadを呼び出すよりも?ありがとう

+0

60秒ごとに?それは反パターンです。 – bbum

+0

どうすれば更新できますか? – King

+0

プッシュ通知に基づくデルタ更新が理想的です。ポーリングは避けなければならない。すべてのデータを削除し、データベース全体をゼロから再作成するのは最悪です。あなたはすでに持っているものを再現するだけで、1トンのバッテリー寿命を生み出す仕事をしています(データベースの内容が60秒ごとに完全に変更されないと仮定して)。 – bbum

答えて

2

あなたはviewDidLoadviewWillAppearなどの方法を自分で呼ぶべきではありません。これらのメソッドをオーバーライドする場合にのみ、superで呼び出す必要があります。

更新するコード(既にloadStudentsになっているようです)を抽出し、viewWillAppearではなくそのメソッドを呼び出します。

https://developer.apple.com/documentation/uikit/uiviewcontroller

3
  1. コアデータはスレッドセーフではありませんを参照してください。任意のスレッドからどんなコンテキストにもアクセスすることはできません。 viewContextpersistentStoreCoordinatorとして読んで扱い、メインスレッドから読んでください。コアデータの変更はすべてperformBackgroundTaskを通過し、渡されたコンテキストを使用する必要があります。
  2. core-dataの下にあるファイルを削除したり、何かを動作させることはできません。最初に、ファイルを削除している間に、他のmanagedObjectContextの読み書きが多くあります。第2のコアデータは、別々のファイルに格納されるいくつかのエンティティに対して外部記憶装置を使用するように設定することができる。第3に、iOSはSQLiteのジャーナリングにWALモードを使用しており、コアデータ永続ストアの(潜在的に大きい)ジャーナルファイルが存在する可能性があります。
  3. コアデータ変更のUIを更新するには、NSFetchedResultsControllerを使用する必要があります。コアデータの設定にpersistentContainer.viewContext.automaticallyMergesChangesFromParent = YESを設定してください。
  4. managedObjectsへのポインタを保持しないでください。彼らはあなたが気づかないうちに文脈から削除することができます、そして、それらにアクセスすることはクラッシュを引き起こします。代わりに、fetchedResultsControllerを使用してください。

は、コア・データ内のすべてのエンティティを削除するには:あなたは完全にデータベースを再初期化している

[self.persistentContainer performBackgroundTask:^(NSManagedObjectContext * _Nonnull) { 
    NSArray* entities = context.persistentStoreCoordinator.managedObjectModel.entities; 
    for (NSEntityDescription* entity in entities) { 
     NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:entity.name]; 
     request.predicate = [NSPredicate predicateWithValue:YES]; 
     request.returnsObjectsAsFaults = YES; 
     NSArray* result = [context executeFetchRequest:request error:NULL]; 
     for (NSManagedObject* i in result) { 
      [context deleteObject:i]; 
     } 
    } 
    [context save:NULL]; 
}]; 
+0

3の実装に問題があります。私はこの新しいコードを同じ関数で更新しますか? – King

+0

私はあなたのコードに基づいてオブジェクトの変更を監視したいのかどうかは不明ですが、NSFetchedResultsControllerが監視するfetchRequestを作成する必要があります。あなたのビューコントローラをデリゲートとして設定し、最低でも 'controllerDidChangeContent:'を実装し、すべてをリロードしてください。その作業が完了したら、他のデリゲートメソッドを実装し、更新が必要なビューの部分のみを更新する必要があります。 –

+0

問題は、私は実際にテーブルや何かを更新するのではなく、実際には辞書を保持している学生です。これは画面を変更するまでヌルを返すようです。私は手動でこれを複製するためにviewWillAppearをロードしようとしましたが、運がありませんでした。私も試みた[self.view setNeedsDisplay];しかし、これはどちらもうまくいきませんでした。このようなことをするために私が呼​​び出せる関数はありますか? – King

関連する問題