Xcode 9.3(Swift 4.1)中的 Codable '没有初始化器'

Posted

技术标签:

【中文标题】Xcode 9.3(Swift 4.1)中的 Codable \'没有初始化器\'【英文标题】:Codable 'has no initializers' in Xcode 9.3 (Swift 4.1)Xcode 9.3(Swift 4.1)中的 Codable '没有初始化器' 【发布时间】:2018-09-09 23:24:14 【问题描述】:

更新到Xcode 9.3(使用Swift 4.1)后,发现如下问题:

    创建一个空项目,向其中添加一个新的 .swift 文件并创建两个新类:

    class CodableOne: Codable 
    
        let some: String
    
    
    
    class CodableTwo: Codable 
    
        var some: String
    
    
    

    构建成功

    CodableOne 添加一个CodableTwo 类型的新常量:

    class CodableOne: Codable 
    
        let some: String
        let another: CodableTwo
    
    
    
    class CodableTwo: Codable 
    
        var some: String
    
    
    

    构建成功

    现在将类 CodableTwo 移动到另一个文件(例如 ViewController.swift)

    构建失败

现在有一个错误,它不会消失。 Codable 类不需要初始化器(如前面的步骤所示)。

任何关于这背后的问题以及如何解决的想法将不胜感激!


附: Xcode 9.2 中不存在问题。清理项目/构建路径,重新安装 Xcode 9.3 也无济于事。

【问题讨论】:

不错的发现——提交了一个错误:bugs.swift.org/browse/SR-7315 @Hamish - 这对我来说似乎为时过早。开启“全模块”编译。 @Rob 这对我来说并没有什么不同(编辑:哦,看起来这取决于“编译源”中文件的顺序)。尽管无论如何它不应该有所作为——编译器不应该在整个模块编译下给你不同的行为(它的目的是允许更积极的优化)。 我和@Hamish 在一起;看起来像一个编译器错误。感谢您打开它。 @Andrew 是的,重新排序确实有助于Whole Module 编译,这在错误报告中有所提及。请在 bugs.swift.org/browse/SR-7315 上为该问题投票 【参考方案1】:

作为mentioned in the comments,我必须做两件事:

    Project settings/Build Settings中将Compilation Mode更改为Whole Module

    重新排序项目设置/构建阶段/编译源下的文件。具体来说,我将有错误的文件放在列表的前面

    Protip:如果您搜索文件名并且有多个结果,将文件拖到较小列表中的顶部仍会将其置于最前面。

【讨论】:

该文章中的步骤在 Xcode 9.3 中已过时,该选项已被移动并重命名。它现在在名为“整个模块”的“编译模式”下。也不会给你赏金,因为你的答案实际上是我所说的在赏金标题中不起作用的确切步骤:P @OscarApeland 谢谢你提供的信息,我编辑了它。当我写这个答案时,我不知道你的赏金,我试图组织我发现有效的解决方案。此外,cmets 中也没有提到将有错误的文件放在前面。我完全反对抄袭和复制粘贴 cmets 的答案,我总是添加一些额外的信息(如果没有,我将我的答案标记为社区 wiki)。 不用担心,很好的答案,它显然对某些人有用:) JIRA 错误刚刚被分配给 Apple 的某个家伙,所以希望我们能很快得到一些真正的答案。 不幸的是,当我想在 Objective C 中创建 Swift 对象时,这不起作用。我尝试将 Swift 文件重新排序到顶部,然后将 ObjC 类重新排序到顶部,但这些都不起作用。【参考方案2】:

这是Swift 4.1 编译器中的一个错误。要解决此问题,请执行 the4kman 的答案中概述的步骤,或者只需在声明中将 let 更改为 var,如下所示:

class C1 : Decodable  
  let str: String 
  // error: Class 'C1' has no initializers - if class C's `c1` is a let constant. 


class C : Decodable 
  var c1: C1 // << Change to `var`, compilation succeeds.

解决方法courtesy of Apples Swift engineers。

如果这个和 4kmans 的答案都没有帮助,您可以将另一个 init 添加到不会编译的模型中。如果您的类有大量变量,只需使init 崩溃以使编译器满意。 Codable 初始化器仍将被合成。

class C1: Decodable 
    let str: String

    @available(*, deprecated, message: "Do not use.")
    private init() 
        fatalError("Swift 4.1") 
    

【讨论】:

谢谢,这成功了。有趣的是,我的一些 Codable 类已通过上面建议的项目设置更改修复,而其他类也需要此修复。 是的,似乎两者都需要。希望他们能尽快解决这个问题 它有效。如果将 init 标记为 private,则不必担心可用性 @manueGE 这更聪明。我忘记了初始化程序有访问控制。更新了答案。【参考方案3】:

即使我的所有类都在同一个文件中,我也遇到了这个问题,但使用结构更深的类似乎可以工作

【讨论】:

那是因为结构会自动合成另一个init【参考方案4】:

试着给你的变量一个这样的初始值(把你的代码改成这个)

class CodableOne: Codable

    var some = ""



class CodableTwo: Codable

    var some = ""


【讨论】:

不,你不能这样做。这将覆盖解码后的值。

以上是关于Xcode 9.3(Swift 4.1)中的 Codable '没有初始化器'的主要内容,如果未能解决你的问题,请参考以下文章

如何在 swift 4.1 和 xcode 9.3 中使用 JSONDecoder 解码嵌套的 JSON 数组和对象?

如何在 Xcode 9.3 中切换到 Swift 4.0?

堆栈视图中的自动约束冲突、Swift 2、iOS 9.3、XCode 7

Xcode 9.3 编译 Swift 源项目永远不会完成

Xcode 9.3 新增能力,优化 Swift 编译生成代码的尺寸

Swift 自动布局在 Xcode 9.3 中不起作用