init来自解码器:Decoder在单独的便利init中导致“无法推断上下文基础”错误

问题描述

我正在尝试对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)
}