Apple は、管理対象オブジェクトを保持する UITableViewCell サブクラスを作成することで (MobileNotes で) この最適化を実現し (KVO の適切な実践)、カスタム セッターで対象のプロパティに KVO を追加しますが、以前のオブジェクトがあった場合は最初に KVO を削除します。prepareForReuse では、オブジェクトを nil に設定します。dealloc では、_object が nil でない場合、KVO を削除します。
これが私の一般的なデモ クラスですが、サブクラス化するよりも、コードを自分のクラスにコピーしたほうがよいでしょう。オブジェクト プロパティの名前を変更します。
MCDManagedObjectTableViewCell.h
#import <CoreData/CoreData.h>
#import <UIKit/UIKit.h>
#import <MCoreData/MCDDefines.h>
NS_ASSUME_NONNULL_BEGIN
MCDATA_EXTERN void * const MCDManagedObjectTableViewCellKVOContext;
@interface MCDManagedObjectTableViewCell<__covariant ManagedObjectType : __kindof NSManagedObject *> : UITableViewCell
// needs to be retained to prevent being turned into a fault
@property (nullable, strong, nonatomic) ManagedObjectType object;
// overrides
// update views from the object's properties
- (void)updateViewsFromCurrentObject NS_REQUIRES_SUPER;
// calls update if on screen otherwise sets a flag and then updates when comes on screen.
- (void)updateViewsFromCurrentObjectIfNecessary NS_REQUIRES_SUPER;
// use addObserver and the MCDManagedObjectTableViewCellKVOContext
- (void)addKVOObserversForObject:(ManagedObjectType)object;
- (void)removeKVOObserversForObject:(ManagedObjectType)object;
@end
NS_ASSUME_NONNULL_END
MCDManagedObjectTableViewCell.m
#import "MCDManagedObjectTableViewCell.h"
void * const MCDManagedObjectTableViewCellKVOContext = (void *)&MCDManagedObjectTableViewCellKVOContext;
@interface MCDManagedObjectTableViewCell ()
@property (nonatomic) BOOL needsToUpdateViews;
@end
@implementation MCDManagedObjectTableViewCell
- (void)setObject:(__kindof NSManagedObject *)object{
if(_object == object){
return;
}
else if(_object){
[self removeKVOObserversForObject:_object];
}
_object = object;
if(object){
[self addKVOObserversForObject:object];
}
[self updateViewsFromCurrentObjectIfNecessary];
}
- (void)addKVOObserversForObject:(__kindof NSManagedObject *)object{
}
- (void)removeKVOObserversForObject:(__kindof NSManagedObject *)object{
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{
if(context != MCDManagedObjectTableViewCellKVOContext){
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
[self updateViewsFromCurrentObjectIfNecessary];
}
- (void)updateViewsFromCurrentObject{
self.needsToUpdateViews = NO;
}
- (void)updateViewsFromCurrentObjectIfNecessary{
if(self.window){
[self updateViewsFromCurrentObject];
}else{
self.needsToUpdateViews = YES;
}
}
- (void)willMoveToWindow:(UIWindow *)window{
if(window && self.needsToUpdateViews){
[self updateViewsFromCurrentObject];
}
}
- (void)prepareForReuse{
[super prepareForReuse];
self.object = nil;
}
- (void)dealloc{
if(_object){
[self removeKVOObserversForObject:_object];
}
}
@end
さらに、セルが複数のプロパティに依存する文字列を表示する必要がある場合、titleForTableViewCell などのカスタム プロパティをモデル サブクラスに追加し、「影響を受けるキー」メカニズムを使用して、その単一のプロパティで KVO を使用できます。