You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI添加自定义Decoder后Absence结构体实例化参数错误求助

问题原因

你遇到的"extra arguments at positions"错误,核心原因是:当你为结构体自定义了init(from: Decoder)解码初始化器后,Swift会自动移除默认生成的成员逐一初始化器。原来的Absence(id: 1, userId: 1, ...)调用方式依赖默认初始化器,现在它不存在了,因此触发参数错误。

解决方案

以下两种方式都能解决问题,可根据代码习惯选择:

方案一:手动添加成员逐一初始化器

在结构体中显式声明与属性匹配的初始化器,同时保留自定义解码逻辑:

struct Absence: Codable, Identifiable, Hashable {
    var id: Int
    var userId: Int
    var start: Date
    var end: Date
    var active: Bool
    var modifiedBy: Int
    var modified: Date
    
    // 手动添加成员逐一初始化器
    init(id: Int, userId: Int, start: Date, end: Date, active: Bool, modifiedBy: Int, modified: Date) {
        self.id = id
        self.userId = userId
        self.start = start
        self.end = end
        self.active = active
        self.modifiedBy = modifiedBy
        self.modified = modified
    }
    
    // 自定义解码初始化器
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        userId = try container.decode(Int.self, forKey: .userId)
        active = try container.decode(Bool.self, forKey: .active)
        modifiedBy = try container.decode(Int.self, forKey: .modifiedBy)
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"
        
        if let startDateString = try? container.decode(String.self, forKey: .start),
           let startDate = dateFormatter.date(from: startDateString) {
            start = startDate
        } else {
            start = Date()
        }
        
        if let endDateString = try? container.decode(String.self, forKey: .end),
           let endDate = dateFormatter.date(from: endDateString) {
            end = endDate
        } else {
            end = Date()
        }
        
        if let modifiedString = try? container.decode(String.self, forKey: .modified),
           let modifiedDate = dateFormatter.date(from: modifiedString) {
            modified = modifiedDate
        } else {
            modified = Date()
        }
    }
    
    static func sampleData() -> Absence {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"

        let startString = "01/01/2021"
        let endString = "01/02/2021"
        let modifiedString = "01/03/2021"

        let startDate = dateFormatter.date(from: startString) ?? Date()
        let endDate = dateFormatter.date(from: endString) ?? Date()
        let modifiedDate = dateFormatter.date(from: modifiedString) ?? Date()

        return Absence(id: 1, userId: 1, start: startDate, end: endDate, active: true, modifiedBy: 1, modified: modifiedDate)
    }
}

方案二:将解码逻辑放到扩展中

把init(from:)移到结构体扩展里,这样结构体仍会保留默认的成员逐一初始化器,无需手动添加:

struct Absence: Codable, Identifiable, Hashable {
    var id: Int
    var userId: Int
    var start: Date
    var end: Date
    var active: Bool
    var modifiedBy: Int
    var modified: Date
    
    static func sampleData() -> Absence {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"

        let startString = "01/01/2021"
        let endString = "01/02/2021"
        let modifiedString = "01/03/2021"

        let startDate = dateFormatter.date(from: startString) ?? Date()
        let endDate = dateFormatter.date(from: endString) ?? Date()
        let modifiedDate = dateFormatter.date(from: modifiedString) ?? Date()

        return Absence(id: 1, userId: 1, start: startDate, end: endDate, active: true, modifiedBy: 1, modified: modifiedDate)
    }
}

// 扩展中实现自定义解码逻辑
extension Absence {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        userId = try container.decode(Int.self, forKey: .userId)
        active = try container.decode(Bool.self, forKey: .active)
        modifiedBy = try container.decode(Int.self, forKey: .modifiedBy)
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"
        
        if let startDateString = try? container.decode(String.self, forKey: .start),
           let startDate = dateFormatter.date(from: startDateString) {
            start = startDate
        } else {
            start = Date()
        }
        
        if let endDateString = try? container.decode(String.self, forKey: .end),
           let endDate = dateFormatter.date(from: endDateString) {
            end = endDate
        } else {
            end = Date()
        }
        
        if let modifiedString = try? container.decode(String.self, forKey: .modified),
           let modifiedDate = dateFormatter.date(from: modifiedString) {
            modified = modifiedDate
        } else {
            modified = Date()
        }
    }
    
    // 扩展实现解码需显式声明CodingKeys
    enum CodingKeys: String, CodingKey {
        case id, userId, start, end, active, modifiedBy, modified
    }
}

补充说明

  • 方案一逻辑直接,适合大多数场景;方案二通过扩展分离解码逻辑,保持结构体主体简洁,但需显式定义CodingKeys。
  • 两种方案都能恢复Absence(id: ...)的实例化方式,解决参数错误问题。

内容的提问来源于stack exchange,提问作者cristian9804

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:54:57