【问题标题】:Key-Value Coding with a key of 'description'带有“描述”键的键值编码
【发布时间】:2013-07-12 12:13:23
【问题描述】:

我正在使用键值编码来简化模型类的更新实例:

@interface NewsItem : NSObject 
{

}

@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *description;
@property (nonatomic, copy) NSString *link;
@property (nonatomic, copy) NSString *date;

使用:

SEL selectorName = NSSelectorFromString(elementName);
if ([self.newsItem respondsToSelector:selectorName])
{
    NSString *sanitisedElement = [self sanitiseElement:self.currentElementData];
   [self.newsItem setValue:sanitisedElement forKey:elementName];
}

这很好用,但“描述”属性对我来说并不“有味道”,因为它覆盖了基本的 NSObject 描述 getter (+ (NSString *)description)。如果现在调用描述 getter,它将在调用者期望类的描述时返回不相关的信息。

是否可以安全地为此类进行键值编码(假设我已通过外部数据源绑定到这些属性名称)?或者更改属性名称并手动检查键/设置值是否明智?

【问题讨论】:

    标签: objective-c properties key-value-coding


    【解决方案1】:

    您始终可以覆盖继承的方法。 通过创建一个其 getter 与继承方法的签名相同的属性,您将覆盖它。

    不好吗?是的,如果您的实现对调试没有用处。

    作为 KVC 和 KVO 的最佳实践,最好避免与常见的继承方法属性和 ivars 发生潜在冲突。 常见的方法是使属性和方法名称更长,并使它们更有可能是唯一的。一种常见的方法是在你所有的前面加上一个对你的类、框架或代码通用的缩写。

    使用 Apple 常用的东西可能会以一种罕见且难以调试的方式咬你一口。 当涉及核心数据时,这样做尤其糟糕。 不要不愿意让事情变得更长。代码完成将为您键入。另外,类特定前缀的一个很好的副作用是伪不仅是伪命名空间,而且你的类特定属性、变量、常量和方法将首先在代码完成中冒泡。

    【讨论】:

      【解决方案2】:

      我认为您将方法与属性混淆了,并且您使事情变得更加复杂。

      给定一个直接包含设置器名称(即:setDate)的 elementName 就足够了,您调用选择器将该参数传递给对象参数:

      SEL selectorName = NSSelectorFromString(elementName); // elementName something like "setDate"
      if ([self.newsItem respondsToSelector:selectorName])
      {
          [self.newsItem performSelector: selectorName withObject: sanitisedElement];
      }
      

      至于描述方法,它已经覆盖了NSObject的描述,所以你有两种选择:用另一种方式命名它,或者保持原样,然后在上调用它超级 当你需要对象描述时,借助 Objective-C 运行时:

      struct objc_super superclass= { self.newItem, [self.newItem superclass] };
      NSString* desc= objc_msgSendSuper(&superclass, @selector(description));
      

      【讨论】:

      • 谢谢,最后一点是不是所谓的method swizzling?
      • 不,这不是混乱。如果你必须使用这样的代码,那肯定表明你的设计存在严重缺陷。
      • 谢谢,正是我检查的原因。
      【解决方案3】:

      您可以在班级中覆盖description。此方法通常仅用于调试 并且没有调用者可以期望该方法的特定输出。

      但我在您的代码中看到了更普遍的问题。仅检查具有 给定的名称存在。这并不意味着该方法对应于一个属性,即使那样,也不意味着该属性有一个 setter。

      例如,每个NSObject 都会响应选择器“init”,所以如果外部 数据源将该键作为“elementName”发送,您的代码将立即崩溃。

      因此,需要一个明确的“已知密钥”列表。但是你也可以 使用从外部元素名称到内部属性的映射 (NSDictionary) 避免任何冲突。

      【讨论】:

      • 这是一个很好的观点,谢谢。我已经改变了我的实现,首先检查一个已知的、可接受的密钥列表,而不仅仅是简单地接受发送的内容。安全总比后悔好。
      猜你喜欢
      • 1970-01-01
      • 2018-01-05
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多