Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 子类化iOS模型对象-适当的设计模式_Objective C_Design Patterns - Fatal编程技术网

Objective c 子类化iOS模型对象-适当的设计模式

Objective c 子类化iOS模型对象-适当的设计模式,objective-c,design-patterns,Objective C,Design Patterns,我担心这是一个相当简单的问题,但在谷歌搜索了很多次之后,我认为我已经超出了预期的结果。我相信我的问题与设计模式有关,但唉,我可能错了 我的应用程序调用一个RESTful API并返回一个由NSDictionary表示的模型对象列表。我将调用nEntity。存在(概念上)多个不同的N实体子类型。nEntity的所有子类型都共享entityID的属性,但每个子类型都有自己独特的属性。nEntity的所有实例都有一个名为readFromDict:(NSDictionary*)d的方法,该方法填充它们各

我担心这是一个相当简单的问题,但在谷歌搜索了很多次之后,我认为我已经超出了预期的结果。我相信我的问题与设计模式有关,但唉,我可能错了

我的应用程序调用一个RESTful API并返回一个由
NSDictionary
表示的模型对象列表。我将调用
nEntity
。存在(概念上)多个不同的N实体子类型。
nEntity
的所有子类型都共享
entityID
的属性,但每个子类型都有自己独特的属性。
nEntity
的所有实例都有一个名为
readFromDict:(NSDictionary*)d
的方法,该方法填充它们各自的属性。此方法由所有
n实体
子类型都符合的协议强制执行。看起来是这样的:

//NNEntity.h

@interface NNEntity : NSObject <NNReadFromDictProtocol>

@property (nonatomic, strong) NSString *entityID;

@end

//NNEntity.m

@implementation NNEntity

- (void)readFromDict:(NSDictionary *)d {
    //set common properties from values in d
    self.entityID = [d objectForKey:@"ID"];
}
@end

//NNSubEntity1.h

@interface NNSubEntity1 : NSEntity <NNReadFromDictProtocol>

@property (nonatomic, strong) NSString *favoriteColor;

@end

//NNSubEntity1.m

@implementation NNSubEntity1

- (void)readFromDict:(NSDictionary *)d {
    [super readFromDict:d];
    //set unique properties from values in d
    self.favoriteColor = [d objectForKey:@"colorPreference]:
}
@end

//NNSubEntity2.h

@interface NNSubEntity2 : NSEntity <NNReadFromDictProtocol>

@property (nonatomic, strong) NSString *middleName;

@end

//NNSubEntity2.m

@implementation NNSubEntity2

- (void)readFromDict:(NSDictionary *)d {
    [super readFromDict:d];
    //set unique properties from values in d
    self.middleName = [d objectForKey:@"middleName]:
}
@end
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];

我假设不是,但是
newEntity
是否正确设置了
entityID
的公共属性以及
middleName
的唯一属性?此外,如果您有更好或更有效的设计方法的想法,我们将不胜感激

这看起来正是你应该做的。有一个基类读入公共属性,还有一个子类读入它们的特定属性

例如,我当前的代码是否最终创建了NNEntity和NNSubEntity2的and实例<代码>nEntity*newEntity=[[NNSubEntity2 alloc]init]

没有。运行此命令时,实例化
NNSubEntity2
,并将结果存储在由其超类键入的变量中,该变量是完全有效的。这允许您调用在超类上定义的任何方法,但实际实例仍然是子类的实例

newEntity是否正确设置了entityID的公共属性和middleName的唯一属性

当然会的。它继承超类中的实例变量、属性和方法


请放心,据我所知,这看起来不错,而且是我以前使用过的模式。

我就是这样做的

// NNEntity.h
@interface NNEntity : NSObject
@property (nonatomic, retain) NSString *entityId;
@end;

// NNEntity.m
@implementation NNEntity
@end;


// NNEntity+KVC.h
@interface NNEnity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
@end

// NNEntity+KVC.m
@implementation NNEntity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
   // Handle this as appropriate to your app.
   // A minimal implementation will throw an exception.
}
@end
同样地,对于您的各种子类。子类上不需要(一定)类别

然后,给定
NSDictionary*dict
,其中包含您的资料:

NNEntity *entity = [[NNEntity alloc] init];
[entity setValuesForKeysWithDictionary:dict];
维奥拉!你完了。对这种方法有一些批评,但鉴于
setValue:forundinedkey:
的强大实现,我认为它是安全的,而且非常灵活

秘密就在苹果漂亮的技术中。本质上,
setValuesForKeysWithDictionary:
迭代您给它的dict的键,并在其接收器中为每个hinvokes
setValue:forKey:
。它看起来是这样的(尽管我确信苹果在幕后对它进行了优化):

我也喜欢这种方法,因为转换为更简单;当您告诉CoreData“渲染”您的模型时,它只会覆盖您的存根模型类,保持KVC类别不变。更重要的是,如果您的
setValue:forundeindekey:
实现顺利,您可以在不破坏应用程序的情况下对后端进行模型更改(这有点不允许,但与出厂解决方案没有太大区别)

当然,我没有提到您需要有选择地选择实例化哪个类。但这是一个更大的设计问题,甚至可能受到API和后端设计的影响。所以我推迟了

此外,正如您在下面的评论中所指出的,属性名称必须匹配。这对某些开发人员来说是一个阻碍,尤其是当您无法同时控制后端和客户端时


试试看。欢迎反馈。

谢谢!一个小的跟进。当我从API中获取字典列表(数组)时,每个字典都有一个
类型
键。我正在考虑在
nEntity
类中创建一个(工厂)方法,比如
+(nEntity*)initWithType:(NSString*)typeStringFromAPI
。这将确定它应该创建并返回的子类的类型。在
nEntity
中使用这样的工厂方法有意义吗?或者我应该创建一个不同的工厂类来实现这一点吗?再次感谢您的回答。在
NSEntity
超类中,您可以将类型映射到类名,并与
NSClassFromString()
组合以获取要实例化的正确类。明白了。谢谢你的指导。我通常不会看到有人问如何做出好的设计+1至::)这很有趣,谢谢你的回复。我假设我的模型对象上的属性必须与我从API获得的键的名称相匹配。如果没有,或者有一个我不期望的新的,则必须通过
setValue:forUndefinedKey:
方法来处理。我相信我会将这种方法与上面的方法结合起来,来确定子类类型并尝试一下。是的,它是正确的——它们必须逐字匹配。这是一个缺点。模型类中的额外或拼写错误的属性不会成为问题,API中的额外或拼写错误的属性将由
setValue:forUndefinedKey:
处理。只要他们匹配,你就会成功。非常感谢这种方法。在过去的一年里一直在使用它,没有任何问题。在我控制API和iOS客户端的情况下,它非常非常有效。
-(void)setValuesForKeysWithDictionary:(NSDictionary *)dictionary {
   NSArray *keys = [dictionary allKeys];
   for (NSString* key in keys) {
      [self setValue:[dictionary valueForKey:key] forKey:key];
   }
}