init(来自解码器:解码器)在单独的便利 init 中导致 "Cannot infer contextual base" 错误
init(from decoder: Decoder) is causing a "Cannot infer contextual base" error in separate convenience init
我正在尝试子class Codable
class 并且在我添加 init(from decoder: Decoder)
函数之前它工作正常。然后,编译器在我的 convenience init 上给了我 2 个错误:
Cannot infer contextual base in reference to member 'geometry'
Extra arguments at positions #2, #3, #4, #5 in call
如果删除解码函数,我不会收到任何错误,并且编码函数会按预期工作。我怎样才能同时拥有便利的初始化和解码器功能?有什么不成文的规定禁止这样做吗?
class GeometryNode: Node {
var values = GeometryNode.Values(shape: .triangle)
enum CodingKeys: String, CodingKey {
case values
case id
case type
case indexPath
}
// NOTE: GeometryNode.Values is a codable struct
// NOTE: GeometryNode.Values.Shape a codable enum
// NOTE: both are defined elsewhere
convenience init(id: String? = nil, shape: GeometryNode.Values.Shape = GeometryNode.Values.Shape.triangle, indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
// Error shows for below call
self.init(id: id, title: title, type: .geometry, icon: icon, color: color, indexPath: indexPath)
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.values, forKey: .values)
}
// Remove this function and error above goes away
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
let container = try decoder.container(keyedBy: CodingKeys.self)
values = try container.decode(GeometryNode.Values.self, forKey: .values)
}
}
extension GeometryNode {
struct Values: Codable {
var shape: Shape
enum Shape: String, CaseIterable, Codable {
case triangle
case rectangle
case oval
var defaultColor: UIColor {
return NodeType.geometry.defaultColor
}
var fontSize: CGFloat {
return 24
}
var icon: UIImage {
return miscValues.icon
}
var color: UIColor {
return miscValues.color
}
private var miscValues: (icon: UIImage, color: UIColor) {
switch self {
case .triangle: return ("".textToImage(fontSize: fontSize)!, color: defaultColor)
case .rectangle: return ("◾️".textToImage(fontSize: fontSize)!, color: defaultColor)
case .oval: return ("⚫️".textToImage(fontSize: fontSize)!, color: defaultColor)
}
}
}
enum CodingKeys: String, CodingKey {
case shape
}
}
}
public class Node: Codable {
var id: String?
var title: String?
var type: NodeType = .geometry
var icon: UIImage?
var color: UIColor?
var indexPath: IndexPath
var defaultColorForType: UIColor {
return type.defaultColor
}
var absoluteCoordinates: CGPoint? {
return CGPoint(x: indexPath.item * kCellWidth, y: indexPath.section * kCellHeight)
}
func dictionary() -> [String: Any] {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
}
enum CodingKeys: String, CodingKey {
case id
case type
case indexPath
}
internal init(id: String? = nil, title: String, type: NodeType = .geometry, icon: UIImage? = nil, color: UIColor? = nil, indexPath: IndexPath) {
self.id = id
self.title = title
self.type = type
self.icon = icon
self.color = color
self.indexPath = indexPath
}
}
extension IndexPath {
enum CodingKeys: String, CodingKey {
case item
case section
}
}
这不是“不成文的”。这是关于 Swift 的一个重要事实。一旦添加了显式 non-convenience 初始化器,初始化器的继承就会停止运行。所以你试图调用一个不存在的初始化器。
如果您真的不需要便利初始化器,那么您可以在该初始化器中调用 super.init
,如下所示:
init(id: String? = nil, shape: GeometryNode.Values.Shape = GeometryNode.Values.Shape.triangle, indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
super.init(id: id, title: title, type: .geometry, icon: icon, color: color, indexPath: indexPath)
}
如果您仍然需要初始化器是 convenience
,您可能需要重写超级的初始化器,因为 Swift 只允许方便的初始化器从同一个 class 调用指定的初始化器。
convenience init(id: String? = nil, shape: GeometryNode.Values.Shape = GeometryNode.Values.Shape.triangle, indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
self.init(id: id, title: title, type: .geometry, icon: icon, color: color, indexPath: indexPath)
}
override init(id: String? = nil, title: String, type: NodeType = .geometry, icon: UIImage? = nil, color: UIColor? = nil, indexPath: IndexPath) {
super.init(id: id, title: title, type: type, icon: icon, color: color, indexPath: indexPath)
}
我正在尝试子class Codable
class 并且在我添加 init(from decoder: Decoder)
函数之前它工作正常。然后,编译器在我的 convenience init 上给了我 2 个错误:
Cannot infer contextual base in reference to member 'geometry'
Extra arguments at positions #2, #3, #4, #5 in call
如果删除解码函数,我不会收到任何错误,并且编码函数会按预期工作。我怎样才能同时拥有便利的初始化和解码器功能?有什么不成文的规定禁止这样做吗?
class GeometryNode: Node {
var values = GeometryNode.Values(shape: .triangle)
enum CodingKeys: String, CodingKey {
case values
case id
case type
case indexPath
}
// NOTE: GeometryNode.Values is a codable struct
// NOTE: GeometryNode.Values.Shape a codable enum
// NOTE: both are defined elsewhere
convenience init(id: String? = nil, shape: GeometryNode.Values.Shape = GeometryNode.Values.Shape.triangle, indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
// Error shows for below call
self.init(id: id, title: title, type: .geometry, icon: icon, color: color, indexPath: indexPath)
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.values, forKey: .values)
}
// Remove this function and error above goes away
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
let container = try decoder.container(keyedBy: CodingKeys.self)
values = try container.decode(GeometryNode.Values.self, forKey: .values)
}
}
extension GeometryNode {
struct Values: Codable {
var shape: Shape
enum Shape: String, CaseIterable, Codable {
case triangle
case rectangle
case oval
var defaultColor: UIColor {
return NodeType.geometry.defaultColor
}
var fontSize: CGFloat {
return 24
}
var icon: UIImage {
return miscValues.icon
}
var color: UIColor {
return miscValues.color
}
private var miscValues: (icon: UIImage, color: UIColor) {
switch self {
case .triangle: return ("".textToImage(fontSize: fontSize)!, color: defaultColor)
case .rectangle: return ("◾️".textToImage(fontSize: fontSize)!, color: defaultColor)
case .oval: return ("⚫️".textToImage(fontSize: fontSize)!, color: defaultColor)
}
}
}
enum CodingKeys: String, CodingKey {
case shape
}
}
}
public class Node: Codable {
var id: String?
var title: String?
var type: NodeType = .geometry
var icon: UIImage?
var color: UIColor?
var indexPath: IndexPath
var defaultColorForType: UIColor {
return type.defaultColor
}
var absoluteCoordinates: CGPoint? {
return CGPoint(x: indexPath.item * kCellWidth, y: indexPath.section * kCellHeight)
}
func dictionary() -> [String: Any] {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
}
enum CodingKeys: String, CodingKey {
case id
case type
case indexPath
}
internal init(id: String? = nil, title: String, type: NodeType = .geometry, icon: UIImage? = nil, color: UIColor? = nil, indexPath: IndexPath) {
self.id = id
self.title = title
self.type = type
self.icon = icon
self.color = color
self.indexPath = indexPath
}
}
extension IndexPath {
enum CodingKeys: String, CodingKey {
case item
case section
}
}
这不是“不成文的”。这是关于 Swift 的一个重要事实。一旦添加了显式 non-convenience 初始化器,初始化器的继承就会停止运行。所以你试图调用一个不存在的初始化器。
如果您真的不需要便利初始化器,那么您可以在该初始化器中调用 super.init
,如下所示:
init(id: String? = nil, shape: GeometryNode.Values.Shape = GeometryNode.Values.Shape.triangle, indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
super.init(id: id, title: title, type: .geometry, icon: icon, color: color, indexPath: indexPath)
}
如果您仍然需要初始化器是 convenience
,您可能需要重写超级的初始化器,因为 Swift 只允许方便的初始化器从同一个 class 调用指定的初始化器。
convenience init(id: String? = nil, shape: GeometryNode.Values.Shape = GeometryNode.Values.Shape.triangle, indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
self.init(id: id, title: title, type: .geometry, icon: icon, color: color, indexPath: indexPath)
}
override init(id: String? = nil, title: String, type: NodeType = .geometry, icon: UIImage? = nil, color: UIColor? = nil, indexPath: IndexPath) {
super.init(id: id, title: title, type: type, icon: icon, color: color, indexPath: indexPath)
}