问题描述
我正在尝试对Codable
类进行子类化,并且在我添加init(from decoder: Decoder)
函数之前,它一直工作良好。然后,编译器在我的便利初始化上给了我两个错误:
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的一个重要事实。一旦添加了显式的非便捷初始化器,初始化器的继承就会停止。因此,您正在尝试调用一个不存在的初始化程序。
,如果您确实不需要便捷的初始化程序,则可以在该初始化程序内调用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只允许便捷的初始化程序调用同一类中的指定初始化程序。
convenience init(id: String? = nil,indexPath: IndexPath) {
let icon = shape.icon
let color = shape.color
let title = shape.rawValue
self.init(id: id,indexPath: indexPath)
}
override init(id: String? = nil,title: String,type: NodeType = .geometry,icon: UIImage? = nil,color: UIColor? = nil,indexPath: IndexPath) {
super.init(id: id,type: type,indexPath: indexPath)
}