Codable 'не имеет инициализаторов' в Xcode 9.3 (Swift 4.1)

После обновления до Xcode 9.3 (который использует Swift 4.1) была обнаружена следующая проблема:

  1. Создайте пустой проект, добавьте к нему новый файл .swift и создайте два новых класса:

    «Создано

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

    Сборка завершена

  2. Добавьте новую константу в CodableOne типа CodableTwo:

    В CodableOne добавлена ​​новая константа

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

    Сборка завершена

  3. Теперь переместите класс CodableTwo в другой файл (например, ViewController.swift).

    CodableTwo перемещен в другой файл

    Сбой сборки.

Теперь есть ошибка, которая никуда не делась. Codable классы не должны требовать инициализаторов (как показано на предыдущих шагах).

Будем очень признательны за любые идеи о том, в чем может быть проблема и как ее можно решить!


P.S. Проблема отсутствует в Xcode 9.2. Ни очистка пути проекта / сборки, ни повторная установка Xcode 9.3 не помогает.


person EBDOKUM    schedule 30.03.2018    source источник
comment
Хорошая находка - обнаружена ошибка: bugs.swift.org/browse/SR-7315   -  person Hamish    schedule 31.03.2018
comment
@Hamish - Мне это кажется преждевременным. Включите компиляцию всего модуля.   -  person Rob    schedule 31.03.2018
comment
@Rob Это не имело для меня значения (отредактируйте: о, похоже, это зависит от порядка файлов в исходных кодах компиляции). Хотя это в любом случае не должно иметь никакого значения - компилятор не должен давать вам другое поведение при компиляции всего модуля (его цель - обеспечить более агрессивную оптимизацию).   -  person Hamish    schedule 31.03.2018
comment
@Rob может подтвердить, что компиляция 'Whole Module' не полностью решает проблему (хотя каким-то образом помогла в небольшом проекте)   -  person EBDOKUM    schedule 31.03.2018
comment
@EBDOKUM - Вы проверяли порядок источников? Было бы неплохо узнать, исправит ли это это и для вас, или выяснить, есть ли здесь еще одна проблема. Этот отчет об ошибке должен быть обновлен детерминированным поведением, чтобы выявить проблему.   -  person Rob    schedule 31.03.2018
comment
Связанная проблема: stackoverflow.com/q/49540520/1974224   -  person Cristik    schedule 31.03.2018
comment
Я с @Hamish; похоже на ошибку компилятора. Спасибо, что открыли.   -  person Rob Napier    schedule 31.03.2018
comment
То же самое, Whole module не помогает. Но изменение порядка файлов в Compile Source устранило проблему. Любые идеи о лучшем подходе будут оценены.   -  person Andrew    schedule 02.04.2018
comment
@Andrew: да, переупорядочивание действительно помогает при компиляции Whole Module, это упоминается в отчете об ошибке. Проголосуйте за проблему на bugs.swift.org/browse/SR-7315   -  person EBDOKUM    schedule 02.04.2018
comment
Была такая же проблема, только все мои декодируемые типы были в одном файле, поэтому переупорядочение компиляции файла ничего не дало. Включение компиляции всего модуля это исправило. Действительно, похоже, это ошибка, но не уверен, какова точная причина.   -  person Nathan Hosselton    schedule 02.04.2018
comment
То же самое и с большим (41k loc) проектом Swift. Скомпилировано отлично с Swift 4 / Xcode9.2, те же проблемы, что и у вас с 4.1 / 9.3. Целый модуль не помогает. Попробую переставить модели в исходниках компиляции. @Hamish, спасибо за отчет.   -  person Oscar Apeland    schedule 03.04.2018
comment
Для меня полная компиляция модуля не имеет значения. Не могу сейчас работать из-за 9.3. Отлично.   -  person nickdnk    schedule 03.04.2018
comment
Помогло переупорядочение списка компиляции. Возможно, и то и другое.   -  person nickdnk    schedule 03.04.2018
comment
То же самое. Я определил конструктор для класса Codable (только для требуемых значений), и теперь он работает.   -  person FrancisNear    schedule 04.04.2018
comment
Включение всего модуля для отладки и изменение порядка файлов в Compile Source (произвольно для затронутых файлов) будет работать.   -  person Caio    schedule 06.04.2018
comment
Включение компиляции всего модуля помогло, переупорядочивание файлов в моем случае не требовалось, спасибо @Rob   -  person AamirR    schedule 13.06.2018


Ответы (4)


Как указано в комментариях < / a>, мне пришлось сделать две вещи:

  1. изменение режима компиляции на весь модуль в настройках проекта / настройках сборки:

    «Установлен

  2. переупорядочите файлы в Настройки проекта / Фазы сборки / Источники компиляции. В частности, я перенес файлы с ошибкой в начало списка.

    Совет: если вы ищете имя файла и есть несколько результатов, перетаскивание файла наверх в этом меньшем списке все равно приведет к его перемещению на передний план.

person Tamás Sengel    schedule 04.04.2018
comment
Шаги в этой статье устарели в Xcode 9.3, этот параметр был перемещен и переименован. Теперь он находится в режиме компиляции под названием Whole Module. Также не буду давать вам награду, поскольку ваш ответ - это буквально те шаги, которые, как я сказал, не сработали в подписи к награде: P - person Oscar Apeland; 05.04.2018
comment
@OscarApeland Спасибо за информацию, я отредактировал ее. Я не знал о вашей награде, когда писал этот ответ, и я попытался организовать решения, которые, как я нашел, работают. Также в комментариях не упоминалось о переносе файлов с ошибками на передний план. Я категорически против плагиата и копирования ответов из комментариев, я всегда добавляю некоторую дополнительную информацию (а если нет, то помечаю свой ответ как вики сообщества). - person Tamás Sengel; 05.04.2018
comment
Не волнуйтесь, отличный ответ, это, очевидно, сработало для некоторых людей :) Ошибка JIRA только что была назначена какому-то парню из Apple, так что, надеюсь, мы скоро получим реальные ответы. - person Oscar Apeland; 06.04.2018
comment
К сожалению, это не работает, когда я хочу создать объект Swift в Objective C. Я попытался переупорядочить файл Swift вверху, а затем класс ObjC вверх, и ничего из этого не работает. - person Josip B.; 20.04.2018

Это ошибка компилятора Swift 4.1. Чтобы обойти это, либо выполните шаги, описанные в ответе 4kman, либо просто измените 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.
}

Временное решение любезно предоставлено инженерами Apple Swift.

Если ни этот, ни ответы the4kmans не помогли, вы можете добавить еще init к моделям, которые не будут компилироваться. Если в ваших классах есть масса переменных, просто отключите init, чтобы удовлетворить компилятор. Инициализатор Codable все равно будет синтезирован.

class C1: Decodable {
    let str: String

    @available(*, deprecated, message: "Do not use.")
    private init() {
        fatalError("Swift 4.1") 
    }
}
person Oscar Apeland    schedule 09.04.2018
comment
Спасибо, это сработало. Интересно, что некоторые из моих классов Codable были исправлены путем изменения настроек проекта, предложенного выше, в то время как другие также требовали этого исправления. - person Halyna Rubashko; 09.04.2018
comment
Да, кажется, требуется и то, и другое. Надеюсь, они быстро разберутся с этим - person Oscar Apeland; 09.04.2018
comment
Оно работает. Если вы отметите инициализацию как private, вам не нужно беспокоиться о доступности - person manueGE; 31.08.2018
comment
@manueGE Это еще умнее. Я забыл, что у инициализаторов есть контроль доступа. Обновленный ответ. - person Oscar Apeland; 31.08.2018

У меня была эта проблема, хотя все мои классы были в одном файле, но использование структур для более глубоких, похоже, работает, хотя

person Hogdotmac    schedule 07.05.2018
comment
Это потому, что структуры автоматически синтезируют другой init - person Oscar Apeland; 08.06.2018

попробуйте дать вашей переменной начальное значение, подобное этому (измените свой код на это)

class CodableOne: Codable{

    var some = ""

}

class CodableTwo: Codable{

    var some = ""

}
person Sanad Barjawi    schedule 10.04.2018
comment
Нет, ты не можешь этого сделать. Это переопределит декодированное значение. - person Oscar Apeland; 10.04.2018