DZLObjcAdditions 2.4.0

DZLObjcAdditions 2.4.0

测试已测试
Lang语言 Obj-CObjective C
许可 MIT
发布最后发布2015年4月

Sam Dods 维护。



  • 作者
  • Sam Dods

有用的 Objective-C '扩展'

该库包括扩展,旨在增强语言并避免需要常见的样板代码。它轻量级,可以在项目中完全安全地安装。

扩展总结

@implementation_combine

类似于正常分类实现,但有一个关键的区别:任何在底层类中已实现的任何方法将被替换,以便保持原始实现不变,并可以使用 dzlSuperdzlCombine 宏来调用。

@implementation_safe

类似于正常分类实现,但底层类中已实现的任何方法不会被替换。如果方法由底层类继承的类实现,则将在底层类中添加分类的实现,并且可以使用 dzlSuper 宏调用父类的实现。

@protocol_implementation

一个协议规范的实现。可以在这里实现任何可选的协议方法,并且这些方法将自动添加到任何符合该协议的类中。(熟悉 Ruby 的人可能会想到这类似于 Objective-C 中的 mixin。)

@synthesize_lazy

合成实例变量获取方法,其中如果底层 ivar 非空,则返回底层 ivar。如果 ivar 为 nil,则将 ivar 设置为新指定类型的实例,并返回。

@class_singleton / @class_singleton_setup

实现具有给定名称的类方法,返回指定类型的单例,带可选的附加设置。

示例

@implementation_combine

这对于尝试分离关注点非常有用。例如,您可能在应用中实现使用分析。您不希望将分析代码添加到视图控制器中,因为它不属于那里。相反,您可以添加一个“组合”类别,从而有效地允许您向原始方法添加新功能。

#import "DZLImplementationCombine.h"

@implementation_combine(MainViewController, CombinedAdditions)

- (void)viewDidAppear:(BOOL)animated
{
  dzlSuper(viewDidAppear:animated); // call the underlying method.

  // add extra functionality.
}

@end

dzlSuper 的调用可以在方法的任何位置进行,也可以完全省略(但这会违背初衷)。

传递给 dzlSuper 宏的代码应该与您在重写此方法(例如上述 viewDidAppear:animated)时发送给 super 的代码完全相同。您应该不要直接调用 super

@implementation_combine 中指定的每个方法都必须由基础类实现,否则会抛出异常(源自 Foundation 断言)。这是因为通常只有将方法与已存在的方法组合才有意义。

如果您希望避免断言,因为这或许是您故意要将方法与非基础类上未实现的方法(因为可能在将来实现)进行组合,可以通过如下方式传递 dzl_no_assert 参数:

@implementation_combine(MainViewController, CombinedAdditions, dzl_no_assert)

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
  dzlCombine(scrollViewDidScroll:scrollView); // call the underlying method

  // add extra functionality.
}

@end

如果想要“组合”一个可能未被底层类合法实现的方法(例如它可能以后会实现),这尤其有用。

dzlCombine 宏的语法与 dzlSuper 宏完全相同,但不需要在基础类上实现该方法。(区别在于如果方法声明了具有 NS_REQUIRES_SUPER 属性的方法,则它不会使编译器的“必须调用 super”警告静音。)

您可以通过调用 dzlCanCombine 来检查底层类是否实现了当前方法,它如果底层类实现了从调用它的相同方法返回的方法,则返回 YES。如果底层类没有实现方法,调用 dzlSuperdzlCombine 不会造成任何问题,因此不需要始终检查。如果方法预期返回特定的值,这很有用。

@implementation_safe

如果您想在现有实现存在的情况下添加到类中的方法,这可能很有用。

#import "DZLImplementationSafe.h"

@implementation_safe(MainViewController, SafeAdditions)

- (void)viewWillAppear:(BOOL)animated
{
  // do something here.

  dzlSuper(viewWillAppear:animated);

  // do some more stuff here.
}

@end

safeSuper 的调用可以在方法的任何位置进行,也可以省略。

传递给 dzlSuper 宏的代码应该与您在重写此方法(例如上述 viewWillAppear:animated)时发送给 super 的代码完全相同。您应该不要直接调用 super

@protocol_implementation

如果您想要为可选协议方法提供默认实现,这可能很有用。

例如,如果您有一个如下定义的协议:

@protocol Talkative
@optional
- (void)saySomething;
@end

您可以为协议方法定义如下默认实现

#import "DZLProtocolImplementation.h"

@protocol_implementation(Talkative)

- (void)saySomething
{
  NSLog(@"Hello world!");
}

@end

然后,采用该协议的类可以不实现可选方法。可选方法可以被调用,并使用默认实现。

@synthesize_lazy

延迟初始化对于许多类型的属性很常见,例如一个 NSMutableArray 实例可以作为如下初始化:

- (NSMutableArray *)transactions
{
  return _transactions ?: (_transactions = [NSMutableArray new]);
}

使用 @synthesize_bonus 指令,它进一步简化为如下

@synthesize_lazy (NSMutableArray, transactions);

您可以在实现中任何位置放置此指令。

@class_singleton

单例是我们创建一个类共享或默认实例的方式,在Cocoa中非常常见(如 NSFileManagerNSNotificationCenter 等)。当我们自己定义时,我们会在整个项目中重复相同的模板代码,通常如下所示

+ (HTTPClient *)defaultClient
{
  static HTTPClient *defaultClient;
  static dispatch_once_t onceToken;

  dispatch_once(&onceToken, ^{
    defaultClient = [HTTPClient new];
  });

  return defaultClient;
}

可以通过在实现中声明 @class_singleton 来简化这一点

@implementation HTTPClient

@class_singleton (HTTPClient, defaultClient);

// rest of implementation code here.

@end

如果您需要在接口中公开您的单例,您可以这样操作,例如

@interface HTTPClient

+ (instancetype)defaultClient;

@end

@class_singleton_setup

有时您可能希望在单例方法中进一步设置您的共享实例。当然,常见的初始化应该在类中做 -init 方法,这个方法将由单例方法调用。但对于共享实例的特定设置,可以很容易地使用 @class_singleton_setup 指令实现

@class_singleton_setup (HTTPClient, defaultClient,
  defaultClient.operationQueue = [NSOperationQueue new];
  defaultClient.operationQueue.maxConcurrentOperationCount = 5;
)

使用此方法,您可以使用与提供给方法的相同名称的变量名称来引用新创建的共享实例。在 Xcode 中,您将非常高兴地看到代码自动完成,这很不错!

安装

作为 CocoaPod 提供使用。

或者,您可以将 DZLObjcAdditions 目录复制到您的项目中。根据需要导入相关的头文件

  • @implementation_combine 在 DZLImplementationCombine.h 中定义
  • @implementation_safe 在 DZLImplementationSafe.h 中定义
  • @protocol_implementation 在 DZLProtocolImplementation.h 中定义
  • @synthesize_lazy 在 DZLSynthesizeLazy.h 中定义
  • @class_singleton / @class_singleton_setup 在 DZLClassSingleton.h 中定义

免责声明

此库利用了Objective-C在运行时“魔术”方法的能力。实现非常简单,我认为它比其他实现类似结果的方法(例如块注入)要干净得多。尽管有些人会建议不要过度使用方法魔术,但在我认为有正当使用案例的情况下,我认为这没有问题。

此外,上述扩展中没有一个真的是编译器指令。它们只是宏。但这些宏是用这种方式编写的,它们需要一个 '@' 符号前缀,我认为这使它们看起来很酷!

推特

如果您喜欢这个,您可以在推特上关注我以获取更多类似内容:[http://twitter.com/dodsios](http://twitter.com/dodsios)!