Ios KVO核心数据和基本访问器
我对iPhone应用程序上的核心数据属性的自定义访问器方法有问题。我想做的不仅仅是拉出原语类型并返回它。我有一个可能的activityType的NSSet,如果对象没有primitiveType,那么我希望在该集合中查找并返回与我的类上的另一个变量匹配的activityType 下面是我为实现这一点而编写的代码。代码的问题是,我对Ios KVO核心数据和基本访问器,ios,cocoa,core-data,key-value-observing,primitive,Ios,Cocoa,Core Data,Key Value Observing,Primitive,我对iPhone应用程序上的核心数据属性的自定义访问器方法有问题。我想做的不仅仅是拉出原语类型并返回它。我有一个可能的activityType的NSSet,如果对象没有primitiveType,那么我希望在该集合中查找并返回与我的类上的另一个变量匹配的activityType 下面是我为实现这一点而编写的代码。代码的问题是,我对[self-willChangeValueForKey:@“type”]的调用导致了一个无限循环,其中程序不断抛出NSLog“将type设置为…”-可能是因为我在访问器
[self-willChangeValueForKey:@“type”]
的调用导致了一个无限循环,其中程序不断抛出NSLog“将type设置为…”-可能是因为我在访问器中调用了willChange
如果我取出[self-willChangeValueForKey:@“type”]
我不会得到循环,程序运行正常,下次我尝试访问对象上的类型时,基本类型被正确调用。但是,当我告诉ManagedObjectContext是时候保存了时,它告诉我任何对象都没有更改-因此,由于我没有调用willChangeValueForKey-对原语类型的更改永远不会为对象保留
- (ActivityType *)type {
[self willAccessValueForKey:@"type"];
ActivityType *myType = [self primitiveType];
[self didAccessValueForKey:@"type"];
if (myType != nil) {
NSLog(@"Use primitive (%@)", [myType myDescription]);
} else {
// 1) find type
NSSet *types = self.myActivityTypes;
NSSet *foundTypes = [types objectsPassingTest:^BOOL(id obj, BOOL *stop) {
ActivityType *object = (ActivityType *) obj;
return ([object.typeName isEqualToString:self.activityTypeName]);
}];
myType = [foundTypes allObjects][0];
NSLog(@"Setting type to %@", [myType myDescription]);
// in this case we should not alert anyone since we are inside the getter?
[self willChangeValueForKey:@"type"];
[self setPrimitiveType:myType];
[self didChangeValueForKey:@"type"];
}
return myType;
}
托管对象属性观察机制将使用访问器检查新旧值。由于您正在更改getter中的值,因此将再次调用getter,因此您的无限循环开始 这种延迟加载实际上不适用于托管对象。您可以在其他位置设置活动类型,例如awakeFromFetch,或者在设置activityTypeName时设置,或者如果不合适,则实现单独的访问器:
-(ActivityType*)calculatedActivityType
{
ActivityType *myType = self.activityType;
if (myType) return myType;
NSSet *types = self.myActivityTypes;
NSSet *foundTypes = [types objectsPassingTest:^BOOL(id obj, BOOL *stop) {
ActivityType *object = (ActivityType *) obj;
return ([object.typeName isEqualToString:self.activityTypeName]);
}];
myType = [foundTypes allObjects][0];
self.activityType = myType;
return myType;
}
这不会导致任何循环,因为您不在任何访问器中 托管对象属性观察机制将使用访问器检查新旧值。由于您正在更改getter中的值,因此将再次调用getter,因此您的无限循环开始 这种延迟加载实际上不适用于托管对象。您可以在其他位置设置活动类型,例如awakeFromFetch,或者在设置activityTypeName时设置,或者如果不合适,则实现单独的访问器:
-(ActivityType*)calculatedActivityType
{
ActivityType *myType = self.activityType;
if (myType) return myType;
NSSet *types = self.myActivityTypes;
NSSet *foundTypes = [types objectsPassingTest:^BOOL(id obj, BOOL *stop) {
ActivityType *object = (ActivityType *) obj;
return ([object.typeName isEqualToString:self.activityTypeName]);
}];
myType = [foundTypes allObjects][0];
self.activityType = myType;
return myType;
}
这不会导致任何循环,因为您不在任何访问器中 另一个解决方案可能是由访问器返回新类型,而不更改基础值类型。而且。。。在当前队列上异步调度更改
dispatch_async(dispatch_get_current_queue(), ^{
[self willChangeValueForKey:@"type"];
[self setPrimitiveType:myType];
[self didChangeValueForKey:@"type"];
});
这并不完美,我可以想象这可能会导致“查找代码”执行多次。另一种解决方案可能是由访问器返回新类型,而不更改基础值类型。而且。。。在当前队列上异步调度更改
dispatch_async(dispatch_get_current_queue(), ^{
[self willChangeValueForKey:@"type"];
[self setPrimitiveType:myType];
[self didChangeValueForKey:@"type"];
});
这并不完美,我可以想象这可能会导致“查找代码”执行多次。为什么不使用set访问器,例如self.type=myType?您正在通过在访问器中执行的操作绕过访问器;将程序放入与发出willChangeValueForKey警告相同的无限循环中。我有一个答案给你,我会把它润色一下,稍后再发。你为什么不直接使用set访问器,例如self.type=myType?您正在通过在访问器中执行的操作绕过访问器;将程序放入与发出willChangeValueForKey警告相同的无限循环中。我有一个答案给你,我会把它润色一下,稍后再发。非常感谢你——这是一个很好的解决方案!作为记录,如果将来有人尝试这样做-使用awakeFromFetch似乎是一个很好的解决方案,并且在实施和测试时,数据似乎保存到了数据库中-至少对象看起来脏了,并且
managedObjectContext.hasChanges
是真的。但是,当程序退出并重新运行时对象仍然是动态创建的,所以在awakeFromFetch中设置对象的部分似乎不是一个好主意。此时对象可能处于不一致的状态。但是calculatedActivityType
的建议就像一个魔咒,非常感谢你——这是一个很好的解决方案!作为记录,如果将来有人尝试这样做-使用awakeFromFetch似乎是一个很好的解决方案,并且在实施和测试时,数据似乎保存到了数据库中-至少对象看起来脏了,并且managedObjectContext.hasChanges
是真的。但是,当程序退出并重新运行时对象仍然是动态创建的,所以在awakeFromFetch中设置对象的部分似乎不是一个好主意。此时对象可能处于不一致的状态。但是calculatedActivityType
的建议非常有效