Шаблон выражения типа "String" не может соответствовать значениям типа "NSStoryboardSegue.Identifier".

Я пытаюсь преобразовать свой код Swift 3 в Swift 4. Я получаю это сообщение об ошибке:

Шаблон выражения типа "String" не может соответствовать значениям типа "NSStoryboardSegue.Identifier".

Это мой код:

override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
    switch segue.identifier {

        case "showVC1":
            // DO SOMETHING
            break

        default:
            break
    }
}

Какой тип следует использовать вместо «String»?


person Ghost108    schedule 05.08.2017    source источник


Ответы (2)


Swift 4 изменил тип свойства identifier с String? на NSStoryboardSegue.Identifier?. Тип: RawRepresentable, RawType из String. Возможно, вам придется изменить свой код на цепочку операторов if или явно использовать rawValue:

switch segue.identifier {
    case let x where x.rawValue == "showVC1":
        // DO SOMETHING
    break
    default:
    break
}
person Sergey Kalinichenko    schedule 05.08.2017
comment
@MartinR У меня пока нет доступа к Swift 4, отвечаю из спецификации. Я удалил часть ответа, в которой предполагалось, что == возможно. Кстати говоря, я очень удивлен, что Apple пошла на кардинальное изменение в этой области: я не могу придумать выгоду от изменения identifier с String на его собственный тип. Спасибо за комментарий! - person Sergey Kalinichenko; 05.08.2017
comment
Аналогичные изменения были внесены для других строк идентификатора, таких как NSImage(named: NSImage.Name). Если я правильно помню, это (противоречиво) обсуждалось в одном из списков рассылки Swift. Я постараюсь найти какую-нибудь ссылку позже, архивы списков в настоящее время отключены. Мне кажется странным, что это изменение не прошло процесс предложения, по крайней мере, я этого не помню. - person Martin R; 05.08.2017
comment
Я нашел ссылку, см. обновленный ответ ниже. - person Martin R; 05.08.2017

Начиная со Swift 4, идентификатор раскадровки является необязательным NSStoryboardSegue.Identifier, который определяется как

extension NSStoryboardSegue {
    public struct Identifier : RawRepresentable, Equatable, Hashable {
        public init(_ rawValue: String)
        public init(rawValue: String)
    }
}

Вы можете включить его rawValue:

    switch segue.identifier?.rawValue {
    case "showVC1"?:
        // do something ...
    default:
        break
    }

Однако рекомендуемый шаблон заключается в определении констант для каждого идентификатора раскадровки:

extension NSStoryboardSegue.Identifier {
    static let showVC1 = NSStoryboardSegue.Identifier("showVC1")
    // other storyboard identifiers ...
}

который затем можно сопоставить с:

    switch segue.identifier {
    case .showVC1?:
        // do something ...
    default:
        break
    }

В обоих примерах «необязательный шаблон» x? (сокращение от .some(x)) используется для сопоставления с необязательным значением.

Подобные типы были введены для других «идентификаторов», например. NSImage.Name, который является типом аргумента NSImage(named:) в Swift 4.

Для получения дополнительной информации см. обсуждение в списке рассылки swift-users, начиная с

Общая идея (насколько я понимаю) заключается в создании отдельных типов для каждого вида идентификатора. В частности (из https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170717/005940.html):

... Мы намеренно не рекомендуем строковый литерал имени. Строковый литерал должен находиться только в одном месте: в определении константы имени. Все остальное должно использовать константу. Компилятор может обеспечить автодополнение и обнаружение опечаток в константе. Строковый литерал этого не понимает.

person Martin R    schedule 05.08.2017