Swift支持面向切面编程吗?

21

我是一名iOS开发人员,想学习面向切面编程。但是Swift支持面向切面编程吗?

2个回答

47
面向切面编程的基础是拦截模式。我们从一个横切需求开始——需要在应用程序的许多部分中发生的事情。然后使用切入点表达式对其进行模块化,通过识别应该应用这个要求的所有地方来实现。这是通过拦截方法调用并编织额外行为来完成的。因此,语言要支持AOP,就必须支持拦截模式。
现在,根据语言的不同,方法拦截可以在编译时、运行时或两者同时应用。在这方面,Swift是一个有趣的案例,因为它支持以下类型的方法调度:
  • 静态/vtable,类似于C++(更快:在测试中占用了约1.1纳秒或更少的方法调用时间)
  • 消息传递,类似于Objective-C(更慢:在测试中占用了约4.9纳秒的方法调用时间)。也称为动态调度迟绑定
如果你扩展NSObject或使用@objc装饰,则会使用消息传递。否则,Swift将恢复到静态/vtable方法调用。
  • 对于静态/vtable类型的调度,只有编译时拦截是可能的。在C++(和Swift)的情况下,这涉及使用预处理器,在实际编译之前生成新源代码。这是一种相当繁琐的方法,需要开发必要的工具以投入更多的精力。虽然它确实提供了最佳的性能。
  • 使用消息传递方式的方法调用,运行时拦截也是可用的。事实上,Objective-C使拦截变得如此容易,以至于没有正式的AOP框架。它可能很有用,但"原材料"是如此出色,没有人费心制作一个。Cocoa的许多最好的功能都利用了Objective-C的动态调度和拦截方法调用的能力。

摘要:

  • 如果你扩展NSObject或使用'@objc'修饰符,则Swift将支持运行时AOP。这方面存在一些怪癖和限制 - Apple关于使用Swift进行KVO的指南将指出大部分问题。
  • 如果您不扩展Objective-C基类或使用'@objc'修饰符,则只有编译时AOP才可能。目前还没有这样的库来提供编译时AOP。此外,编译时AOP的缺点是它只适用于您拥有源代码的类。

NB1:某些语言(如Java)采用静态/虚函数表式的方法调度仍然支持运行时方法拦截。这是因为它们依赖于虚拟机以及类加载器,另一个钩子入口。实际上,由于这一点,Java仍被归类为“后期绑定”语言。

NB2:在某些限制下,技术上可以对已编译成机器码二进制文件进行编译时织入。第一种情况是因为实现工作量很高,必须针对每个平台重复执行,因此没有太多的工具来支持它。第二种情况是它限制了可用的AOP功能。


(有点老的)关于vtable和消息分派的性能分析来源:https://dev59.com/L0fRa4cB1Zd3GeqP_roM#907880 - Jasper Blues
相关问题:Swift类应该扩展NSObject吗?https://dev59.com/j2Ag5IYBdhLWcg3wBXAR - Jasper Blues
嘿,Jasper!虽然这是一个“旧”的答案,但还是感谢你。现在已经是2018年了,你是否知道在Swift 4中有关AOP方面的任何变化或者新的东西可以利用来实现这个功能呢? - Jimbo
1
你好 @Jimbo!我看到了Swift5中关于编译时AOP/装饰器的提案。除此之外没有其他消息。 - Jasper Blues

6

不幸的是,Swift本身目前没有运行时支持。您需要依赖Objective-C桥接。

这里有一个全新的AOP库适用于iOS,用Objective-C编写,且支持Swift。

https://github.com/MO-AI/MOAspects

只有“前置方法”和“后置方法”可用,但在大多数情况下,它足以解决您的问题。 请注意,在针对纯Swift类/方法拦截时,可能需要将“dynamic”关键字添加到您的函数中,以确保正常工作。

MOAspects优于两个最著名的Objective-C AOP库Aspects和BlockInjection。 Aspects不支持类方法拦截和多次钩入类层次结构中的方法。 BlockInjection存在一个重大问题,即不支持64位。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接