Core data 核心数据:避免在多个关系中保留周期

Core data 核心数据:避免在多个关系中保留周期,core-data,memory-management,ios,Core Data,Memory Management,Ios,我仍在通过iOS开发和处理核心数据来学习我的方法,并且刚刚遇到了保留周期 阅读《核心数据编程指南》后,我的理解是,在处理完关系后,可以使用托管对象上下文方法refreshObject:mergeChanges,以确保中断保留周期 假设我在一个部门和它的员工之间有一个多对多的关系,在我的代码中我从部门访问员工关系,这是否意味着我现在需要遍历每个员工对象并调用refreshObject:mergeChanges方法?在代码中,这将是 for (Employee *anEmployee in depa

我仍在通过iOS开发和处理核心数据来学习我的方法,并且刚刚遇到了保留周期

阅读《核心数据编程指南》后,我的理解是,在处理完关系后,可以使用托管对象上下文方法
refreshObject:mergeChanges
,以确保中断保留周期

假设我在一个部门和它的员工之间有一个多对多的关系,在我的代码中我从部门访问员工关系,这是否意味着我现在需要遍历每个员工对象并调用
refreshObject:mergeChanges
方法?在代码中,这将是

for (Employee *anEmployee in department.employees) {
  //some code that accesses an employee's properties

  [context refreshObject:enEmployee mergeChanges:NO];
}
似乎如果我不这样做,我访问的每个employee对象现在都将包含对部门的引用,我将以retain cycles结束

我的理解正确吗?这是处理核心数据中多个关系时的标准方法吗?谢谢。

正如您可以在中检查的那样,保留周期对于防止释放不需要的对象是必要的。这意味着您在使用对象时保留该对象


如果您已处理完该对象,并且希望将其转化为故障,则应使用
refreshObject:mergeChanges
,以便尽可能地处理内存。它不一定会在关系的另一端释放对象,它只会为核心数据设置一个标志,在必要时可以将对象转换为故障。

我已经编写了两个助手方法(见下文),通过使用实体模型的内省来打破整个对象图的保留循环。您可以在收到内存警告通知后使用它来释放核心数据模型中可通过该特定对象访问的部分所持有的任何内存

@interface CoreDataHelper(Private)

+ (void)faultObjectImpl:(NSManagedObject *)managedObject mergeChanges:(FaultChangeBehaviour)mergeChanges;
+ (void)faultObjectGraphForObject:(NSManagedObject *)managedObject handledObjects:(NSMutableArray *)handledObjects mergeChanges:(FaultChangeBehaviour)mergeChanges;

@end

@implementation CoreDataHelper

typedef enum FaultChangeBehaviour {
    FaultChangeBehaviourIgnore,
    FaultChangeBehaviourReapply,
    FaultChangeBehaviourMerge
} FaultChangeBehaviour;



+ (void)faultObjectGraphForObject:(NSManagedObject *)managedObject keepChanges:(BOOL)keepChanges {
    NSMutableArray *handledObjects = [NSMutableArray arrayWithCapacity:64];
    FaultChangeBehaviour mergeBehaviour = keepChanges ? FaultChangeBehaviourReapply : FaultChangeBehaviourIgnore;
    [self faultObjectGraphForObject:managedObject handledObjects:handledObjects mergeChanges:mergeBehaviour];
}

+ (void)refreshObject:(NSManagedObject *)managedObject {
    [self faultObjectImpl:managedObject mergeChanges:FaultChangeBehaviourMerge];
}

+ (void)refreshObjectGraphForObject:(NSManagedObject *)managedObject {
    NSMutableArray *handledObjects = [NSMutableArray arrayWithCapacity:64];
    [self faultObjectGraphForObject:managedObject handledObjects:handledObjects mergeChanges:FaultChangeBehaviourMerge];
}

@end

@implementation CoreDataHelper(Private)

+ (void)faultObjectImpl:(NSManagedObject *)managedObject mergeChanges:(FaultChangeBehaviour)mergeChanges {
    //Only fault if the object is not a fault yet and is not in a modified state or newly inserted (not saved yet)
    BOOL isFault = [managedObject isFault];
    BOOL isTemporary = [[managedObject objectID] isTemporaryID];
    BOOL isUpdated = [managedObject isUpdated];

    NSDictionary *changedValues = [managedObject changedValues];

    if (isUpdated && (mergeChanges == FaultChangeBehaviourIgnore)) {
        NSLog(@"Warning, faulting object of class: %@ with changed values: %@. The changes will be lost!", 
              NSStringFromClass([managedObject class]), changedValues);
    }

    if (!isFault && !isTemporary) {
        [[managedObject managedObjectContext] refreshObject:managedObject mergeChanges:(mergeChanges == FaultChangeBehaviourMerge)];
        if (mergeChanges == FaultChangeBehaviourReapply) {
            for (NSString *key in changedValues) {
                id value = [changedValues objectForKey:key];
                @try {
                    [managedObject setValue:value forKey:key];
                } @catch (id exception) {
                    NSLog(@"Could not reapply changed value: %@ for key: %@ on managedObject of class: %@", value, key, NSStringFromClass([managedObject class]));
                }

            }
        }
    }
}

+ (void)faultObjectGraphForObject:(NSManagedObject *)managedObject handledObjects:(NSMutableArray *)handledObjects mergeChanges:(FaultChangeBehaviour)mergeChanges {

    if (managedObject != nil && ![managedObject isFault] && ![handledObjects containsObject:[managedObject objectID]]) {
        [handledObjects addObject:[managedObject objectID]];
        NSEntityDescription *entity = [managedObject entity];

        NSDictionary *relationShips = [entity relationshipsByName];
        NSArray *relationShipNames = [relationShips allKeys];

        for (int i = 0; i < relationShipNames.count; ++i) {
            NSString *relationShipName = [relationShipNames objectAtIndex:i];
            if (![managedObject hasFaultForRelationshipNamed:relationShipName]) {
                id relationShipTarget = [managedObject valueForKey:relationShipName];
                NSRelationshipDescription *relationShipDescription = [relationShips objectForKey:relationShipName];

                if ([relationShipDescription isToMany]) {
                    NSSet *set = [NSSet setWithSet:relationShipTarget];
                    for (NSManagedObject* object in set) {
                        [self faultObjectGraphForObject:object handledObjects:handledObjects mergeChanges:mergeChanges];
                    }
                } else {
                    NSManagedObject *object = relationShipTarget;
                    [self faultObjectGraphForObject:object handledObjects:handledObjects mergeChanges:mergeChanges];
                }
            }
        }

        [self faultObjectImpl:managedObject mergeChanges:mergeChanges];
    }
}

@end
@接口CoreDataHelper(专用)
+(void)faultObjectImpl:(NSManagedObject*)managedObject合并更改:(FaultChangeBehavior)合并更改;
+(void)faultObjectGraphForObject:(NSManagedObject*)managedObject handledObjects:(NSMutableArray*)handledObjects mergeChanges:(FaultChangeBehavior)mergeChanges;
@结束
@CoreDataHelper的实现
typedef枚举FaultChangeBehavior{
你可以忽略,
请重新申请,
故障切换行为合并
}错误行为;
+(void)faultObjectGraphForObject:(NSManagedObject*)managedObject keepChanges:(BOOL)keepChanges{
NSMutableArray*handledObjects=[NSMutableArray阵列容量:64];
FaultChangeBehavior MergeBehavior=keepChanges?FaultChangeBehavior重新应用:FaultChangeBehavior忽略;
[self-faultObjectGraphForObject:managedObject handledObjects:handledObjects合并更改:合并行为];
}
+(void)refreshObject:(NSManagedObject*)managedObject{
[self-faultObjectImpl:managedObject合并更改:FaultChangeBehaviorMerge];
}
+(void)refreshObjectGraphForObject:(NSManagedObject*)managedObject{
NSMutableArray*handledObjects=[NSMutableArray阵列容量:64];
[self-faultObjectGraphForObject:managedObject handledObjects:handledObjects合并更改:FaultChangeBehaviorMerge];
}
@结束
@实现CoreDataHelper(专用)
+(void)faultObjectImpl:(NSManagedObject*)managedObject合并更改:(FaultChangeBehavior)合并更改{
//仅当对象不是故障且未处于修改状态或新插入(尚未保存)时才出现故障
BOOL isFault=[managedObject isFault];
BOOL isTemporary=[[managedObject objectID]isTemporaryID];
BOOL isUpdated=[managedObject isUpdated];
NSDictionary*ChangedValue=[managedObject ChangedValue];
if(isUpdated&(mergeChanges==faultchangebhaviorignore)){
NSLog(@“警告,类%@的错误对象,更改值:%@。更改将丢失!”,
NSStringFromClass([managedObject class]),ChangedValue);
}
如果(!isFault&!isTemporary){
[[managedObject managedObjectContext]刷新对象:managedObject合并更改:(合并更改==FaultChangeBehaviorMerge)];
如果(合并更改==故障更改行为重新应用){
for(NSString*输入ChangedValue){
id值=[changedValues对象forkey:key];
@试一试{
[managedObject setValue:value-forKey:key];
}@catch(id异常){
NSLog(@)无法在类%@、值、键、NSStringFromClass([managedObject class])的managedObject上为键%@重新应用更改的值%@;
}
}
}
}
}
+(void)faultObjectGraphForObject:(NSManagedObject*)managedObject handledObjects:(NSMutableArray*)handledObjects mergeChanges:(FaultChangeBehavior)mergeChanges{
if(managedObject!=nil&&![managedObject isFault]&&&![handledObjects containsObject:[managedObject objectID]]{
[handledObjects addObject:[managedObject objectID]];
NSEntityDescription*实体=[managedObject实体];
NSDictionary*关系=[entity relationshipsByName];
NSArray*relationShipNames=[relationShips allKeys];
对于(int i=0;i