Не удалось найти файл *.json внутри проекта Xcode 12.

Я впервые пробую Swift (5.3) и Xcode (12). Задача состоит в том, чтобы разобрать файл *.json, который уже существует поблизости.

Честно говоря, добавить файл в проект Xcode сложнее, чем собственно его парсить: куда бы я его ни положил, он всегда не находится. Этот ответ не помог, потому что в инспекторе файлов нет раздела Target Membership (думаю, он был переименован или перемещен куда-то еще в Xcode 12; может быть, я ошибаюсь; во всяком случае, не смог его найти также).

Я также заметил разницу в поведении раздела Целевое членство при создании нового Проекта и нового Пакета Swift. Если это проект, то появляется целевое членство. Поскольку я создал пакет, этот раздел для меня недоступен.

Может ли кто-нибудь помочь мне понять, что здесь происходит?


  • Структура проекта (называемого TryParseJSON, он организован как пакет Swift) выглядит следующим образом:

    TryParseJSON/
      Package.swift
      Sources/
        TryParseJSON/
          main.swift # defines `findPath(to:)` and calls `findPath(to: "persons.json")`
          Person.swift
          persons.json # this file is not found
    
  • Содержимое файла Package.swift следующее:

    // swift-tools-version:5.3
    
    import PackageDescription
    
    let package = Package(
        name: "TryParseJSON",
        products: [
            .executable(name: "TryParseJSON", targets: ["TryParseJSON"]),
        ],
        targets: [
            .target(
                name: "TryParseJSON",
                dependencies: [],
                resources: [
                    .copy("persons.json"),
                ]
            ),
        ]
    )
    
  • Путь в .copy("persons.json") относится к main.swift; если я указываю путь относительно Package.swift (.copy("Sources/TryParseJSON/persons.json")), Xcode не находит JSON (показывается предупреждение "found 1 file(s) which are unhandled"), и пакет все равно не работает; с .copy("persons.json") нет предупреждения.

  • Файл persons.json был добавлен с помощью ФайлНовыйФайл › Пустой (категория Другое) › переименовать в лица.json.

  • Функция findPath:

    func findPath(to file: String) -> URL {
        guard
            let path = Bundle.main.url(forResource: file, withExtension: nil)
        else {
            fatalError("File \(file) was not found") // this is called
        }
    
        return path
    }
    
  • Эта функция определена и вызывается внутри main.swift:

    let path = findPath(to: "persons.json")
    

Я не знаю, как это работает, я не знаю, что именно я должен сделать, чтобы добавить нового члена в цель, я не знаю, что такое цели и продукты, и я разочарован тем, что добавление файлов в Xcode требуется это много усилий.


person Dima Parzhitsky    schedule 17.10.2020    source источник
comment
Не могли бы вы указать свой Package.swift в вопросе, пожалуйста.   -  person JeremyP    schedule 17.10.2020


Ответы (1)


В Swift 5.3 пакеты могут добавлять и обрабатывать ресурсы, не относящиеся к коду. Однако Package.swift должен явно определить их. Сделайте это, добавив ресурсы в цель:

targets: [
  .target(
    name: "TryParseJSON",
    resources: [
      .copy("persons.json")
    ]
  )
]

Это скопирует его в Bundle, надеюсь, в нужное место. Если нет, может потребоваться дополнительная конфигурация.

Обратите внимание, что путь указан относительно каталога, содержащего исходные коды для цели. Apple рекомендует создать подкаталог внутри исходного каталога с именем Resources. Если вы это сделаете, вам нужно

      .copy("Resources/persons.json")

Кроме того, убедитесь, что Package.swift определяет инструменты Swift 5.3 вверху следующим образом:

// swift-tools-version:5.3

Также имеет значение, как вы пытаетесь извлечь URL-адрес файла, когда вам нужно получить к нему доступ. Согласно документам Apple, вы всегда должны использовать Bundle.module.url(forResource:,withExtension:) для получения URL-адреса ресурса. . Итак, в приведенном выше случае используйте

guard let resourceUrl = Bundle.module.url(forResource: "persons",withExtension: "json")
else { /* fail */ }
person JeremyP    schedule 17.10.2020
comment
Спасибо! Я пробовал это, к сожалению, безуспешно. Я обновил ответ с подробностями. - person Dima Parzhitsky; 17.10.2020
comment
@DimaParzhitsky Я сделал это сейчас для себя, так что я лучше понимаю вещи. Ваша главная проблема сейчас, я думаю, это функция, которую вы используете для получения URL-адреса. Должно быть Bundle.module.url(...), а не Bundle.main.url(...). Я обновил свой ответ. - person JeremyP; 18.10.2020