FDModel 是一个为 Objective-C 设计的模型层,旨在极大地简化从远程对象(即 NSDictionary、NSString、NSValue)创建模型对象的过程。用户只需要在他们的 FDModel 子类中覆盖 remoteKeyPathsToLocalKeyPaths 方法来定义远程 key path 与本地 key path 的映射关系,所有这些本地 key path 的解析、转换和设置都将自动处理。
FDModel 的另一个主要好处是保证:如果使用标识符创建了 FDModel 的一个实例,那么在给定时间内存中只会存在该模型的一个实例。为了自动化此过程,用户只需要在他们的子类中覆盖 remoteKeyPathForUniqueIdentifier 方法。所有使用标识符创建的 FDModel 实例都将存储在一个弱引用缓存中,这确保了如果 FDModel 的任何实例被任何其他东西引用,它总是在内存中。在内存吃紧的情况下,此缓存将清除不再被任何东西引用的模型。
FDModel 还提供了在对象被设置在本地键路径之前将其转换的能力。例如,如果 FDModel 的一个子类有一个名为 'status' 的属性,并且用户想转换远程键路径解析的值,他们可以实现一个名为 'statusTransformer' 的方法,该方法返回一个 NSValueTransformer。当即将设置状态属性时,此转换器将自动使用。
默认情况下,所有 FDModel 对象只保存在内存中。模型对象可以保存到 FDModelStore 中,如果尝试创建具有相应标识符的模型,则自动从存储中读取已保存到模型存储的任何模型。
FDModel
暴露了一个 NSRecursiveLock
,它被 FDModel 以及 FDModelProvider
和 FDModelStore
(及其具体子类)内部使用,以确保对 FDModel 任何实例的修改都发生在单个线程上。如果您需要修改 FDModel 的任何属性,则建议在做出更改时利用此锁,并在 UI 线程之外进行操作。
这是为了防止在多个线程上访问可变模型,这通常会导致崩溃或其他不良行为(例如 https://devforums.apple.com/message/1079642)。
FDModel 支持两种方法。这两种方法都假设您的 Xcode 项目正在使用模块。
以下是 "游戏" 模型对象的实现细节的简单示例。该项目包含了 iOS 和 Mac 示例项目,展示了如何从 NSDictionary 中实际创建这个游戏对象的实例。
FDGame.h
@interface FDGame : FDModel
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *genre;
@property (nonatomic, copy) NSDate *releaseDate;
@end
FDGame.m
@implementation FDGame
+ (NSString *)remoteKeyPathForUniqueIdentifier
{
return @"game_id";
}
+ (NSDictionary *)remoteKeyPathsToLocalKeyPaths
{
FDGame *game = nil;
NSDictionary *remoteKeyPathsToLocalKeyPaths = @{
@"name" : @keypath(game.name),
@"genre" : @keypath(game.genre),
@"release_date" : @keypath(game.releaseDate)
};
return remoteKeyPathsToLocalKeyPaths;
}
+ (NSValueTransformer *)releaseDateTransformer
{
FDValueTransformer *releaseDateTransformer = [FDValueTransformer registerTransformerWithName: @"ReleaseDateTransformer"
block: ^id(id value)
{
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"MM-dd-yyyy";
NSDate *releaseDate = [dateFormatter dateFromString: value];
return releaseDate;
}];
return releaseDateTransformer;
}
- (NSString *)description
{
NSString *description = [NSString stringWithFormat: @"<%@: %p; id = %@; name = %@; genre = %@; release date = %@>",
[self class],
self,
self.identifier,
_name,
_genre,
_releaseDate];
return description;
}
@end