Categories

虽然我们知道这样写很丑, 但是我们应该要在我们的 category 方法前加上自己的小写前缀以及下划线,比如- (id)zoc_myCategoryMethod。 这种实践同样被苹果推荐

这是非常必要的。因为如果在扩展的 category 或者其他 category 里面已经使用了同样的方法名,会导致不可预计的后果。实际上,实际被调用的是最后被加载的那个 category 中方法的实现(译者注:如果导入的多个 category 中有一些同名的方法导入到类里时,最终调用哪个是由编译时的加载顺序来决定的,最后一个加载进来的方法会覆盖之前的方法)。

如果想要确认你的分类方法没有覆盖其他实现的话,可以把环境变量 OBJC_PRINT_REPLACED_METHODS 设置为 YES,这样那些被取代的方法名字会打印到 Console 中。现在 LLVM 5.1 不会为此发出任何警告和错误提示,所以自己小心不要在分类中重写方法。

一个好的实践是在 category 名中使用前缀。

  • 例子
    • @interface NSDate (ZOCTimeExtensions)
      - (NSString *)zoc_timeAgoShort;
      @end
      
  • 不要这样
    • @interface NSDate (ZOCTimeExtensions)
      - (NSString *)timeAgoShort;
      @end
      

分类可以用来在头文件中定义一组功能相似的方法。这是在 Apple的 Framework 也很常见的一个实践(下面例子的取自NSDate 头文件)。我们也强烈建议在自己的代码中这样使用。

我们的经验是,创建一组分类对以后的重构十分有帮助。一个类的接口增加的时候,可能意味着你的类做了太多事情,违背了类的单一功能原则。

之前创造的方法分组可以用来更好地进行不同功能的表示,并且把类打破在更多自我包含的组成部分里。

@interface NSDate : NSObject <NSCopying, NSSecureCoding>
@property (readonly) NSTimeInterval timeIntervalSinceReferenceDate;
@end
@interface NSDate (NSDateCreation)
+ (instancetype)date;
+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
+ (instancetype)dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti;
+ (instancetype)dateWithTimeIntervalSince1970:(NSTimeInterval)secs;
+ (instancetype)dateWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)date;
// ...
@end