Xcode报错:Cannot convert value of type ‘String’ to expected argument type ‘Date’
Xcode报错:Cannot convert value of type ‘String’ to expected argument type ‘Date’

Xcode报错:Cannot convert value of type ‘String’ to expected argument type ‘Date’

前情提要

在Xcode中下面的代码:

let missions: [Mission] = Bundle.main.decode("missions.json")

Text(mission.launchDate ?? "N/A")

显示如下的报错输出:

Cannot convert value of type 'String' to expected argument type 'Date'
Initializer 'init(_:)' requires that 'Date' conform to 'StringProtocol'

经排查原因为:Mission的launchDate为Date?类型,但Text需要一个String类型。

struct Mission: Codable, Identifiable {
    struct CrewRole: Codable {
        let name: String
        let role: String
    }
    let id: Int
    let launchDate: Date?
    let crew: [CrewRole]
    let description: String
    var displayName: String {
        "Apollo \(id)"
    }
    var image: String {
        "apollo\(id)"
    }
}

虽然launchDate是一个可选值,并且如果为空会返回“N/A”,但是即使有值时,也需要将Date转换为String类型,否则编译器会报错。

解决方案

我们只需要将Date格式为String类型后,就可以在Text()中显示输出。

因此,我们可以在Mission结构中添加如下代码:

var formattedLaunchDate: String {
    launchDate?.formatted(date: .abbreviated, time: .omitted) ?? "N/A"
}

Formatted(date:time:)是Date类型的一个方法,是Swift中用于将Date类型格式化字符串的一种方法,用来格式化日期和时间。date: .abbreviated表示简短的日期格式,例如Oct 3, 2024。.time: .omitted表示不显示时间部分。

修改后的Mission结构:

struct Mission: Codable, Identifiable {
    
    struct CrewRole: Codable {
        let name: String
        let role: String
    }
    
    let id: Int
    let launchDate: Date?
    let crew: [CrewRole]
    let description: String
    
    var displayName: String {
        "Apollo \(id)"
    }
    
    var image: String {
        "apollo\(id)"
    }
    
    // 将日期格式化为字符串
    var formattedLaunchDate: String {
        launchDate?.formatted(date: .abbreviated, time: .omitted) ?? "N/A"
    }
}

然后,我们在Text()中直接调用新定义的formattedLaunchDate计算变量:

Text(mission.formattedLaunchDate)

我们的日期就可以正常显示。

问题得到解决。

延伸问题

如果你是在解码JSON文件的日期字段,按照上述操作后,Xcode报错:

Failed to decode missions.json from bundle due to type mismatch – Expected to decode Double but found a string instead.

那是因为JSONDecoder默认的日期解码策略和JSON文件中的日期格式不匹配导致的。默认情况下,JSONDecoder会尝试将日期解码为Double类型的时间戳格式(即Unix时间戳。表示自1970年以来的秒数)。

1728180541

但因我所读取的JSON文件中的日期是字符串格式。

"launchDate": "1968-10-11" 

所以,JSONDecoder无法识别这些日期字符串,就导致类型不匹配的错误。

catch DecodingError.typeMismatch(_, let context) {
    fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
}

因此,我们的解决方案就是让JSONDecoder使用正确的日期格式,可以通过自定义DateFormatter来解析JSON中的日期字符串。

解析代码为:

let decoder = JSONDecoder()

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"  // 解析的日期格式
decoder.dateDecodingStrategy = .formatted(formatter)  // 告诉解码器使用这个格式来解析日期

设置完DateFormatter后,问题全部得到解决。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注