CoreData 瞬态关系示例
Posted
技术标签:
【中文标题】CoreData 瞬态关系示例【英文标题】:CoreData transient relationship example 【发布时间】:2013-04-23 05:27:51 【问题描述】:有人有关于如何在 CoreData 中对 transient 对一 relationship 进行建模和编码的示例吗?例如,我有 2 个具有一对多关系的实体。医生和预约。现在我想在医生实体上建立一个名为 mostRecentAppointment 的临时关系。在 xcode 设计器中建模很简单,但我不确定实现方面。我还应该实施逆向吗?看起来很傻。
【问题讨论】:
很确定不支持开箱即用的瞬态关系,您必须手动合并一个。这可能无法直接回答您的问题,但实现mostRecentAppointment
关系的最简单方法是在您的数据访问层类中创建一个方法,并使用带有日期描述谓词的NSFetchRequest
检索它
嗯。设计器确实允许您将关系标记为瞬态。所以那里似乎有什么东西。我希望利用它附带的 KVO 和缓存,因为我不想每次访问对象时都执行 fetchrequest。希望有类似正常瞬态属性的东西。
嗨。你解决问题了吗?我正在解决[一个相关问题](***.com/questions/42812151/…) 似乎暂时的关系没有按预期工作。
【参考方案1】:
看看我最近写的这段代码,将图像缓存在 NSManagedObject 中:
首先,您在模型中定义一个 transient 属性(请注意,如果您的瞬态属性指向 CoreData 支持的对象类型以外的对象类型,您将在模型中保留为“Undefined
” )
然后,您为该实体重新生成 NSManagedObject 子类或手动添加新属性,头文件应如下所示:
@interface Card : NSManagedObject
@property (nonatomic, retain) NSString * imagePath;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * order;
@property (nonatomic, retain) NSString * displayName;
@property (nonatomic, retain) UIImage *displayImage;
@end
这里我们将transient属性的class改为实际的class类型
例如displayImage
这里的输入是UIImage
。
在实现文件(或扩展类)中,您为瞬态属性实现 getter/setter:
-(UIImage*)displayImage
//Get Value
[self willAccessValueForKey:@"displayImage"];
UIImage *img = (UIImage*)[self primitiveValueForKey:@"displayImage"];
[self didAccessValueForKey:@"displayImage"];
if (img == nil)
if ([self imagePath]) //That is a non-transient property on the object
img = [UIImage imageWithContentsOfFile:self.imagePath];
//Set Value
[self setPrimitiveValue:img forKey:@"displayImage"];
return img;
希望对你有所帮助。
【讨论】:
我知道如何做到这一点,它比你说的要复杂一些,因为你需要处理缓存失效和故障。不管我的问题是关于短暂的关系而不是属性。几乎没有关于短暂关系的信息。因此我发布了这个问题。例如,当事物被添加或删除到正常的一对多关系(添加正常约会)时,如何处理缓存失效。【参考方案2】:您需要做的是添加一个名为 newAppointment 的约会类型实体,并在每次为给定医生创建新约会时设置它。就这么简单。
始终按照苹果的建议实施逆向验证和核心数据效率。
或者,您可以为约会添加时间戳,并使用 NSPredicates 在给定医生的链接约会中搜索最新约会。
【讨论】:
KVO 支持怎么样?我宁愿像普通的瞬态属性一样利用 CoreData 框架。 这是真的,但在大多数情况下,您需要在创建时将实际预约与医生联系起来,反之亦然,因此您仍然需要医生进行实例化。鉴于这是最近的约会。虽然我同意 KVO 是一个很好的方法,但在这种情况下可能有点矫枉过正。 Ofc 这是一个例子。我的应用程序有点复杂。所以KVO就派上用场了。由于关系未保存(瞬态),您如何在应用程序启动时重新建立链接? 老实说,我从来没有需要短暂的关系,所以把所有东西都放在店里,但要知道它们是如何工作的。在这种情况下,虽然我会在商店中保留最新的约会并使用 NSPredicates 来搜索最新的 TBH。主要原因是这两个部分无论如何都在数据存储中,我需要拉出医生或预约才能在此示例中使用。 就像我说的,这只是一个例子。我正在寻找有关如何实现瞬态关系的详细信息。你有什么方便的代码吗?【参考方案3】:在这种情况下,要覆盖的适当方法是Doctor
实体中的-awakeFromFetch
,例如:
- (void)awakeFromFetch
[super awakeFromFetch];// important: call this first!
self.mostRecentAppointment = <something>; // normal relationship
self.mostRecentAppointment.doctor = self; // inverse relationship
在模型设计器中,将正常和反向关系都标记为瞬态。应该是这样的。
【讨论】:
你不必同时设置关系和逆关系。设置一个关系,Core Data 会处理反向关系。【参考方案4】:好吧,您只需在自己的示例程序中尝试一下,正确设置的时间不会超过一个小时。
我的猜测是 --- 不需要额外的编码。如果 Apple 关于 CoreData 的文档是正确的,那么普通属性/关系和“瞬态”之间的唯一区别是后者不会持久化,这意味着当您“保存”时它不会更新持久性存储。
我猜想否则它的所有方面都是完整的,包括 KVO/KVC 合规性、撤消支持、验证和通过删除规则自动更新。唯一的问题是,在重新获取实体后 --- 瞬态关系将始终为零。
为此 --- 我当然不建议将临时关系设置为“非可选”,因为对于大多数实体而言,大多数时间它很可能为空。
我会建立一个反向关系(也是暂时的,并且明智地命名)并且让两个删除规则都是“Nullify”。
到目前为止是暂时的关系。
但是我想出了一个替代方案,试图解决几乎相同的问题。我的“约会”是相关的约会之一,但不仅仅是“最新的”,而是第一个“未完成”的约会。非常相似的逻辑。
我添加了一个新的计算属性到我的“医生”实体生成的 NSManagedObject 子类中,而不是暂时的关系,如下所示:
@interface XXDoctor (XXExtensions)
/**
@brief Needs manual KVO triggering as it is dependent on a collection.
Alternatively, you can observe insertions and deletions of the appointments, and trigger KVO on this propertyOtherwise it can be auto-
@return the latest of the to-many appointments relation.
**/
@property (readonly) XXAppointment *latestAppointment; // defined as the
@end
实施:
#import "XXDoctor".h"
#import "XXAppointment.h"
@implementation XXDoctor (XXExtensions)
// this won't work because "appointments" is a to-many relation.
//+ (NSSet *)keyPathsForValuesAffectingLatestAppointment
// return [NSSet setWithObjects:@"appointments", nil];
//
- (XXAppointment *) latestAppointment
NSInteger latestAppointmentIndex = [self.appointments indexOfObjectPassingTest:^BOOL(XXAppointment *appointment, NSUInteger idx, BOOL *stop)
*stop = (appointment.dateFinished == nil);
return *stop;
];
return (latestAppointmentIndex == NSNotFound) ? nil : [self.appointments objectAtIndex: latestAppointmentIndex];
@end
【讨论】:
抱歉,您还没有真正回答我的问题,即如何正确实现瞬态关系。我无法在 Apple 文档中找到有关此主题的更多信息。你有这个特定主题的链接吗? 我做到了。不需要实施。只需将关系标记为“瞬态”,重新生成您的 NSManagedObject 子类,然后随意使用。没有进一步实施。我现在在我的应用程序中成功地使用了一对一和一对多的瞬态关系,没有任何特殊问题。 啊,在我的应用程序中,我还定义了与瞬态关系的反比关系,并将它们也设置为瞬态。我在我的应用程序中使用瞬态关系(而不是我建议的计算属性)的原因是 UndoManager 将它们视为正常的 CoreData 更改,并且知道如何优雅地还原它们。以上是关于CoreData 瞬态关系示例的主要内容,如果未能解决你的问题,请参考以下文章