Swift 没有在 CAGradientLayer 上调用 class init 方法

Swift not calling class init method on CAGradientLayer

我有一个 Objective-C 的 'CAGradientLayer' 子类,它覆盖了 '+ (CAGradientLayer *)layer' 初始值设定项。它已正确包含在我的 Bridging-Header

#import "ONCGradientLayer.h"

@implementation ONCGradientLayer

+ (ONCGradientLayer *)gradientLayer {
    return [ONCGradientLayer layer];
}

+ (ONCGradientLayer *)layer {
    ONCGradientLayer * layer = [super layer];
    layer.colors = @[(id)[[UIColor colorWithWhite:0.0 alpha:1] CGColor], (id)[[UIColor colorWithWhite:0.1 alpha:1] CGColor]];
    layer.startPoint = CGPointMake(0, 0);
    layer.endPoint = CGPointMake(0, 1);
    return layer;
}

通过调用 [ONCGradientLayer layer][ONCGradientLayer gradientLayer]

,这一切都按照 Objective-C 的预期工作

当我尝试从 swift 调用它时,我得到一个编译器警告,该方法已重命名 init,所以我必须调用 ONCGradientLayer() 但是,不起作用,并且永远不会调用覆盖的初始化程序。

我可以通过添加一个不同名称的初始值设定项来解决这个问题:

+ (ONCGradientLayer *)swiftInit {
    return [ONCGradientLayer layer];
}

我可以在 swift 中使用 ONCGradientLayer.swiftInit()

成功调用它

发生什么事阻止我调用 ONCGradientLayer() 并获取覆盖的初始化程序?

更新: 我可以通过将 ONCGradientLayer() 重构为使用 init 方法来使 ONCGradientLayer() 工作,但我仍然很好奇为什么其他方法不起作用。

- (instancetype)init {
    if (self = [super init]) {
        self.colors = @[(id)[DEFAULT_BACKGROUND_COLOR CGColor], (id)[[UIColor colorWithWhite:.1 alpha:1] CGColor]];
        self.startPoint = CGPointMake(0, 0);
        self.endPoint = CGPointMake(0, 1);
    }
    return self;
}

这都是关于一个名为 Clang Importer. 的 Swift 组件,它负责将 Objective-C 方法名称翻译成 Swift 方法名称(反之亦然)。

Clang Importer 假定如果 Objective C class 具有与 class 同名的 class 方法,除了前缀和小写,可能由 with 扩展, 它是一个 class 工厂方法。

它还假定class工厂方法与名称构造方法相同的初始化器有效相同,并且完全隐藏相应的工厂方法,因为对于 ARC,两者之间没有有意义的区别。

EXAMPLE: NSString has factory method stringWithFormat: and initializer initWithFormat:.

Well, string is the same as NSString stripped of its prefix and lowercased; so the Clang Importer assumes that stringWithFormat: is a factory method. Moreover, it is constructed just like initWithFormat:, so the Clang Importer assumes they are effectively the same, and hides the former.

Therefore you have to say String(format:), meaning String.init(format:), in Swift. [The Clang Importer also strips the with, but that's another story.] There is no String.withFormat(_:) (or similar) in Swift, matching Objective-C stringWithFormat:.

这正是您的 ONCGradientLayer 和 gradientLayer 的情况。您的 class 方法遵循 class 工厂方法命名约定。因此,多亏了 Clang Importer,如果有一个 init —— 确实有 —— 那么 class 工厂方法就被隐藏了。因此,您必须改为调用 init,在 Swift.

中说 ONCGradientLayer()

但是您没有将 init 定义为 return 修改后的 ONCGradientLayer,因此结果是没有您修改的普通层。

如果你不喜欢那样,你有两个选择。你已经发现它们是什么了!

  • 更改 class 工厂名称,例如makeGradientLayer。 (这正是您通过提供名称 swiftInit 所做的。)

  • 或者,定义init到return一个ONCGradientLayer,修改方式与layer相同。 (你也是这么做的。)