fetchedResultsController述語があります。ここで"isOpen == YES"
closeCurrentClockSetを呼び出すときは、そのプロパティを[〜#〜] no [〜#〜]に設定します。したがって、tableViewに表示されなくなります。
いくつかの理由で、これは起こっていません。
誰かが私がこれを理解するのを手伝ってもらえますか?
-(void)closeCurrentClockSet
{
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"isOpen == YES"];
NSArray *fetchedObjects =
[self fetchRequestForEntity:@"ClockSet"
withPredicate:predicate
inManagedObjectContext:[myAppDelegate managedObjectContext]];
ClockSet *currentClockSet = (ClockSet *)fetchedObjects.lastObject;
[currentClockSet setIsOpen:[NSNumber numberWithBool:NO]];
}
-
カスタムfetchRequestForEntity:withPredicate:inManagedObjectContextメソッドを呼び出すことにより、まったく同じアプローチを使用して、さらにいくつかのメソッドがあります。
これらのメソッドでは、プロパティを変更すると、tableViewが正しく更新されます。しかし、上記のこれ(closeCurrentClockSet)はそうではありません!理由がわかりません。
-
私のfetchedResultsControllerの実装は、Appleのドキュメントからのものです。
また、別の詳細。アプリをバックグラウンドに送信した場合。アプリを閉じて再度開くと、tableViewが更新されて表示されます!
私はここstackOverflowで以前の質問に従うために最善を尽くしました。運がない。私もこれを骨にNSLoggedしました。オブジェクトは正しくフェッチされています。それは正しいものです。 isOpen Propertyは正しく更新されています[〜#〜] no [〜#〜]。しかし、何らかの理由で、fetchedResultsControllerがtableViewを更新しません。
私は、reloadDataやperformFetchの呼び出しなど、いくつかの「ハンマー」ソリューションを試しました。しかし、それはうまくいきませんでした。またはそれらを使用するのは理にかなっています...
編集:スクラッチ、それDID動作、resultsControllerでperformFetchの直後にreloadDataを呼び出すしかし、reloadDataを使用すると、解決策が得られます。さらに、すべてのアニメーションが削除されます。IコントローラにtableViewを自動更新させたい。
誰かが私がこれを理解するのを手伝ってくれる?
どんな助けでも大歓迎です!
ありがとうございました、
ヌーノ
編集:
完全な実装。
fetchedResultsControllerは、かなり標準的で簡単です。他のすべてはAppleのドキュメントからのものです
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController) {
return _fetchedResultsController;
}
NSManagedObjectContext * managedObjectContext = [myAppDelegate managedObjectContext];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"ClockPair"
inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSString *predicate = [NSString stringWithFormat: @"clockSet.isOpen == YES"];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:predicate]];
NSSortDescriptor *sortDescriptor1 =
[[NSSortDescriptor alloc] initWithKey:@"clockIn" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:@"Root"];
_fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Appleのドキュメントからのボイラープレートコード:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (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:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationLeft];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id )sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
最初の更新:
追跡[managedObjectContext hasChanges]は、必要に応じてYESを返します。ただし、fetchedResultsControllerはtableViewを更新しません
2回目の更新
didChangeObject:atIndexPath:呼び出されませんこの特定のケースでは!私にはさらに2つのメソッドがあり、まったく同じコードで、たまたま別のエンティティになっています。そして、それらは完全に機能します。これを指摘してくれてありがとう@Leonardo
TH UPDATEこのメソッドは、同じルールに従います。しかし、実際には機能します。
- (void)clockOut
{
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"isOpen == %@", [NSNumber numberWithBool:YES]];
NSArray * fetchedObjects =
[self fetchRequestForEntity:@"ClockPair"
withPredicate:predicate
inManagedObjectContext:[myAppDelegate managedObjectContext]];
ClockPair *aClockPair = (ClockPair *)fetchedObjects.lastObject;
aClockPair.clockOut = [NSDate date];
aClockPair.isOpen = [NSNumber numberWithBool:NO];
}
誰かが私が欠けているかもしれないものについて他のアイデアを持っていますか?
ありがとうございました、
ヌーノ
OK、問題を説明してから、FRCのバグかどうかを判断させていただきます。バグだと思われる場合は、Appleにバグレポートを提出する必要があります。
フェッチ結果コントローラーの述語は次のようになります。
NSString *predicate = [NSString stringWithFormat: @"clockSet.isOpen == YES"];
これはブール値の有効な述語です。 clockSet
エンティティの関係に従い、そのisOpen
属性を取得します。 YES
の場合、それらのオブジェクトはオブジェクトの配列に受け入れられます。
ここまではいいと思います。
ここで、clockSet.isOpen
属性の1つをNO
に変更すると、そのオブジェクトがテーブルビューから消えることが期待されます(つまり、述語と一致しなくなったため、オブジェクトから削除する必要があります。フェッチされたオブジェクトの配列)。
だから、あなたがこれを持っているなら...
[currentClockSet setIsOpen:[NSNumber numberWithBool:NO]];
次に、currentClockSet
と関係のある最上位オブジェクトは、フェッチされた結果のFRC配列から「消える」はずです。
しかし、あなたはそれが消えるのを見ません。その理由は、FRCによって監視されているオブジェクトが変更されていないためです。はい、述語キーパスが変更されましたが、FRCはClockPair
のエンティティを保持し、ClockSet
エンティティは実際に変更されました。
通知が飛び交うのを見て、舞台裏で何が起こっているかを確認できます。
とにかく、FRCはフェッチを実行するときにキーパスを使用しますが、フェッチされたオブジェクトの実際のセットにないオブジェクトへの変更を監視しません。
最も簡単な回避策は、このキーパスオブジェクトを保持するオブジェクトの属性を「設定」することです。
たとえば、ClockPair
にもisOpen
属性があることに気づきました。あなたが逆の関係を持っているなら、あなたはこれをすることができます...
currentClockSet.isOpen = NO;
currentClockSet.clockPair.isOpen = currentClockSet.clockPair.isOpen;
実際には値をまったく変更していないことに注意してください。ただし、セッターが呼び出され、KVOがトリガーされたため、プライベートDidChange通知が呼び出され、オブジェクトが変更されたことをFRCに通知しました。したがって、チェックを再評価して、オブジェクトを含める必要があるかどうかを確認し、変更されたキーパス値を見つけて、期待どおりに実行します。
したがって、FRC述語でキーパスを使用する場合、その値を変更すると、FRC配列内のすべてのオブジェクトに戻って「ダーティアップ」し、それらのオブジェクトが通知に含まれるようにする必要があります。オブジェクトの変更について渡されました。醜いですが、フェッチ要求を保存または変更して再フェッチするよりもおそらく優れています。
あなたが私を信じていないことを知っているので、先に進んで試してみてください。それが機能するためには、オブジェクトのFRC配列内のどのアイテムが変更の影響を受けるかを知り、FRCに変更を認識させるためにそれらを「突く」必要があることに注意してください。
もう1つのオプションは、前述したように、コンテキストを保存して値を再フェッチすることです。コンテキストを保存したくない場合は、ストアから更新せずに、フェッチに現在のコンテキストの更新を含めることができます。
FRCが監視しているオブジェクトへの変更を偽造することが、他のエンティティへの重要なパスである述語の再評価を達成するための最良の方法であることがわかりました。
さて、これがバグであるかどうかは議論の余地があります。個人的には、FRCがキーパスを監視する場合は、ここで見られるように部分的にではなく、ずっと監視する必要があると思います。
それが理にかなっていることを願っています。バグレポートを提出することをお勧めします。
同様の問題が発生しました。
私はこの質問がかなり古いことを知っていますが、これが他の誰かに役立つことを願っています:
最も簡単な方法は、親オブジェクトに_lastUpdated: NSDate
_という名前の新しいプロパティを導入することでした。
いくつかのConversation
を含むMessages
がありました。メッセージのisRead
フラグが更新されるたびに、ConversationOverviewViewController
sのみを表示するConversation
の更新が必要でした。さらに、NSFetchedResultsController
のConversationOverviewVC
はConversation
sのみをフェッチし、Message
については何も知りません。
メッセージが更新されるたびに、私はmessage.parentConversation.lastUpdated = NSDate()
を呼び出しました。これは、更新を手動でトリガーする簡単で便利な方法です。
お役に立てれば。
後[currentClockSet setIsOpen:[NSNumber numberWithBool:NO]];
管理対象オブジェクトのコンテキストを保存できますか?
NSError *saveError = nil;
if( ![[myAppDelegate managedObjectContext] save:&saveError] ) {
// handle error saving context
}
コンテキストを保存した後、UITableView
が正しく更新されると思います。これが、アプリをバックグラウンドに送信することが機能する理由である可能性があります。 Core Dataスタックは、バックグラウンドに移行したときにメインのNSManagedObjectContext
で保存を実行するようにアプリケーションのデリゲートで設定されていると思われます。