【问题标题】:Swift not calling class init method on CAGradientLayerSwift 没有在 CAGradientLayer 上调用类初始化方法
【发布时间】:2020-06-06 04:42:07
【问题描述】:

我有一个 'CAGradientLayer' 的 Objective-C 子类,它覆盖了 '+ (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];
}

我可以使用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;
}

【问题讨论】:

    标签: ios swift calayer cagradientlayer


    【解决方案1】:

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

    Clang Importer 假设如果一个 Objective C 类有一个类方法,除了前缀和小写之外,与该类同名,可能被with 扩展,它是一个类工厂方法。

    它还假设一个类工厂方法与名称构造相同的初始化器实际上是相同的,并且完全隐藏相应的工厂方法,因为使用 ARC 之间没有有意义的区别两个。

    示例: NSString 有工厂方法stringWithFormat: 和初始化器initWithFormat:

    好吧,string 与 NSString 相同,去掉了前缀并小写了;所以 Clang 导入器假定 stringWithFormat: 是一个工厂方法。此外,它的构造就像initWithFormat:,因此 Clang 导入器假定它们实际上是相同的,并隐藏前者。

    因此你必须在 Swift 中说 String(format:),意思是 String.init(format:)。 [Clang Importer 也去掉了 with,但这是另一回事。] Swift 中没有 String.withFormat(_:)(或类似的),匹配 Objective-C stringWithFormat:

    这正是您的 ONCGradientLayer 和 gradientLayer 的情况。您的类方法遵循类工厂方法命名约定。因此,多亏了 Clang 导入器,如果存在 init——并且确实存在——那么类工厂方法就被隐藏了。因此,您必须改为调用 init,在 Swift 中说 ONCGradientLayer()

    但是您没有定义 init 来返回修改后的 ONCGradientLayer,因此结果是没有您修改的普通层。

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

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

    • 或者,定义init 以返回一个ONCGradientLayer,其修改方式与您在layer 中所做的相同。 (这也是你所做的。)

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      • 2014-07-29
      • 2015-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多