覆盖或扩展 UIColor 以支持某些协议

Overriding or extending UIColor to support certain protocols

我正在尝试子class 或扩展 UIColor 以支持一些协议。

假设我的协议如下所示:

public protocol MyProtocol {
    init(myValue: Any) throws
}

由于某些原因,我无法实现它,我也不知道为什么。

这适用于所有其他 classes:

class MyTestClass:SomeOtherClass, MyProtocol{
    required init(myValue: Any) throws{
        super.init(someOtherClassInitializer:Any)
    }
}

没问题。但是,如果我尝试使用 UIColor 执行此操作,则会出现错误。

class MyColor:UIColor, MyProtocol{

    required init(myValue: Any) throws {
        super.init(red: 0, green: 0, blue: 0, alpha: 1)
    }
}

首先,它抱怨 required:Coder-init。好的,提供那个。致命错误很好。然后它抱怨另一个初始化。它说

'required' initializer 'init(_colorLiteralRed:green:blue:alpha:)' must be provided by subclass of 'UIColor'

奇怪的弯曲,但还好。让我们也补充一下。我单击 "Fix",它添加了这个存根:

@nonobjc required convenience init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) {
    fatalError("init(_colorLiteralRed:green:blue:alpha:) has not been implemented")
}

然后它给了我两个错误,一个与我刚刚单击 "Fix" 的错误相同(它添加了另一个相同的初始化,并且一次又一次),另一个是:

Overriding non-@objc declarations from extensions is not supported

我没有在扩展中,但我想这个便利初始化程序可能是?但是为什么需要我实现——而且又不可能实现?


我知道,"you shouldn't subclass UIColor",但我想如果我想让它起作用,我必须这样做。 这是一个奇怪的请求,所以一些背景信息;我正在使用 Apollo 库执行 GraphQL 网络任务,它使用脚本将预期响应转换为强类型 swift 对象,这样我就可以在代码中使用它们而无需手动反序列化它们。它运行良好。

大多数值都是标准和原始类型,如 String、Int 等,但有时服务器会尝试向我发送一个 class 的对象,这对 Swift 来说是陌生的,并且这些将默认为 String。这很好。但我想要更花哨的。例子;值“2020-01-14T10:00:00”可能会作为名为 DateTime 的 class 从服务器返回,但由于 "DateTime" 在我的项目或 Swift,自动生成的 classes 会将它们作为 String 值包含,我必须将其视为字符串。

因为我想一直使用这些自动生成的 classes 直到视图,这意味着我必须在任何使用它的地方将它从 String 转换为 Date。另一种选择是创建我自己的所有 classes 版本,并将所有外国 classes 转换为我自己的版本,例如 String->Date,这很无聊。我希望它自动为我完成。

好处是 - Apollo 允许我创建自己的自定义标量。所以对于这个 "DateTime -> Date"-example,我可以简单地说

typealias DateTime = Date
extension DateTime, JSONDecodable, JSONEncodable{ ... }

这让 Apollo 知道有一个对应的 class 可以将 class "DateTime" 的对象转换成。协议 JSONDecodable 和 JSONEncodable 告诉它如何(我自己实现)。 使用它,将生成自动生成的代码,以便任何日期值现在都是日期时间(例如日期)而不是字符串。不错!

所以我想,为什么不利用这个优势呢?我们还从这个 API 收到十六进制颜色。所以我们已经做到了 API returns 十六进制代码(“#FFFFFF”)作为 class HexColorCode。 默认情况下,这只会变成一个 String ,所以我必须在任何我想使用它的地方用十六进制初始化一个 UIColor 。但我现在正尝试使用相同的逻辑,以便自动生成的 classes 实际上有一个我可以在任何地方直接使用的 UIColor。但是发生了以上情况。

我假设 Date,作为 Foundationpublic struct,具有一些自由度,而 UIColor,从 UIKit 继承自 NSObjectopen class,没有。但是什么以及为什么?


我认为可以创建一个 "wrapper"-object,所以我可以说 "HexColorCode" 是一个独立的 class,它有一个 color-field,我不得不说 myView.backgroundColor = apiModel.color.color 而不是 apiModel.color。但我真的希望它能起作用..

我检查了你的情况,我也有编译器混淆的印象。
但可能有解决办法。以下代码为我编译没有问题:

public protocol MyProtocol {
    init(myValue: Any) throws
}

class MyColor:UIColor {
    convenience init(myValue: Any) throws {
    self.init(red: 0, green: 0, blue: 0, alpha: 1)
    }
}

编辑:

抱歉:虽然此代码可以编译,但缺少协议。
这是(希望)正确的代码:

class MyColor:UIColor, MyProtocol {
    required convenience init(myValue: Any) throws {
    self.init(red: 0, green: 0, blue: 0, alpha: 1)
    }
}