【问题标题】:Is there a way to add an extension to AnyObject?有没有办法向 AnyObject 添加扩展?
【发布时间】:2015-08-12 19:56:42
【问题描述】:

在 Objective-C 中,我创建了一个非常方便的 NSObject 类别(用 Swift 术语来说是扩展),它增加了在运行时将任意键/值对添加到任何 NSObject 的能力。它使用关联对象将可变字典附加到对象,然后提供 get 和 set 方法来获取/设置键/值对到/从该字典。只需要几行代码。

这使得在运行时将任意键/值对附加到任何对象(包括系统创建的对象)成为可能。那是关键。在某些情况下,系统框架会向您返回一个对象,而您需要能够为其附加一个值。

这个技巧还可以创建具有新实例变量的类别。 (好吧,它们不是真的,但它确实允许您向类别中的对象添加新的状态变量。)

这在 Swift 1.2 中是不可能的,因为:

  • Swift 没有像 NSObject 这样的所有对象的基类 目标-C。它使用 AnyObject,这是一个协议。
  • 斯威夫特 1.2 不允许扩展协议。

在 Swift 1.2 下我不得不放弃这个。

但是 Swift 2 允许扩展协议。我想“太好了,现在我可以添加我的扩展,让我可以将键/值对添加到 AnyObject!”

不开心。

当我尝试为 AnyObject 创建扩展时:

extension AnyObject: AssociatedObjectProtocol

我收到错误消息

'AnyObject' 协议无法扩展

啊!如此接近,但没有。似乎该语言明确禁止扩展 AnyObject。为什么会这样,有什么办法可以解决吗?

我不经常在 NSObject 上使用我的类别,但当我这样做时,它就是救命稻草。我想将它添加到我的 Swift 技巧包中。

我可以像在 Objective-C 中那样将它添加到 NSObject 中,但这意味着它只适用于从 NSObject 继承的对象 - 使其不适用于原生 Swift 类。

【问题讨论】:

标签: protocols swift2


【解决方案1】:

不幸的是,不存在与您想要的完全相同的解决方法。所以我建议制定一个协议,该协议具有添加默认实现的扩展:

protocol A: AnyObject {}

// in Swift you would rather use this
protocol A: class {}

// add default implementations
extension A {
    func aMethod() {
        // code
    }
}

// Example
class B: A {}

// use the method
B().aMethod()

这种方法不会使所有的类都自动符合这个协议(但只有类可以符合它)。所以你必须让他们符合你自己。由于您不经常使用它,这将是一个合理的解决方案。

【讨论】:

  • 我不完全理解你的建议。你是说我会在协议中定义方法签名,然后提供代码作为我需要的任何类的扩展?这意味着我必须为每个目标类复制扩展中的代码,对吗?
  • @DuncanC 在这种情况下,您无需在协议中定义任何要求,您可以将扩展中的方法与任何符合它的类一起使用,而无需额外代码(在答案中添加示例)
  • 我无法理解您答案中的伪代码。
  • @DuncanC 你说的伪代码是什么意思?此代码是有效的 Swift 2 代码。
  • 协议扩展很奇怪......但这个答案是惊人的和有用的。我在这里奇怪的问答中使用了它:stackoverflow.com/a/33697088/8047 谢谢!
【解决方案2】:

按照@Qbyte 的回答,声明NSObject 符合协议意味着整个Cocoa/UIKit/Foundation 世界中的几乎每个类都将继承该功能:

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        print("This is me, doing something.")
    }
}

extension NSObject: MyProtocol { }

您刚刚使 99% 的 Apple 框架类符合 MyProtocol。您可以通过从NSObject 继承或简单地遵循它来使您自己的类符合MyProtocol

【讨论】:

  • 这并不是真正的解决方案。使用“扩展 NSObject”是完全合法的,但这意味着对于您自己的类,您需要使您自己的所有类都符合 NSObjectProtocol
  • 这个答案很好,但是使用它并不能为您提供一些基本的 Swift 编译时检查。例如,如果你想要一个变量var string: String { return self as! String } 并且你调用arrayInstance.string 编译器不会告诉你任何东西,但是操作是不可能的,就像你尝试["element"] as! String 编译器告诉你操作总是失败
  • 如果您要使 NSObject 符合您的协议,该协议已扩展为包含默认行为,那么直接扩展 NSObject 而不是使用协议会有所不同吗?
  • @Gobe,将它作为一个单独的协议,然后使 NSObject 符合该协议的好处是,如果您愿意,您还可以使 other 事物符合该协议至。如果您只扩展 NSObject,则必须将 NSObject 子类化,这可能并不总是可取的。
【解决方案3】:

我觉得你面前有答案。扩展 NSObject 在 Swift 中也能完美运行。 (可能不会早于 6 年 ?)

extension NSObject { }

【讨论】:

  • 发帖者知道他们可以扩展 NSObject。他们想要一种方法来扩展所有原生 Swift 类。他们是这样写的:“我可以像在 Objective-C 中一样将它添加到 NSObject,但这意味着它只适用于从 NSObject 继承的对象 - 使其不适用于原生 Swift 类。”
  • 这里已经有一篇关于它的帖子:stackoverflow.com/a/30176106/5899647 唯一的方法是从任何地方继承 NSObject 并扩展它,或者像@Aaron Rasmussen 给出的示例那样自定义协议。这就是为什么我说答案已经在这里了。
  • 另外,根据您的具体需要,您还可以创建全局函数和/或全局变量。 (甚至可以是单例以使其“更干净”)
猜你喜欢
  • 2020-04-09
  • 2021-06-24
  • 2012-10-07
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 2019-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多