'приведено к любому', но свойство имеет тип UIColor - PullRequest
1 голос
/ 26 марта 2019

Это

NSAttributedString.Key.foregroundColor: view.tintColor

Вызывает это предупреждение

Expression implicitly coerced from 'UIColor?' to 'Any'

Но не должно ли это предупреждение быть

Expression implicitly coerced from 'UIColor?' to 'UIColor'

Так как это свойство

NSAttributedString.Key.foregroundColor

имеет тип UIColor?

screenshot

Примечание: Это начало происходить только после обновления до Swift 5 , Xcode 10.2 .

Вот еще контекст:

override func viewDidLoad() {
        super.viewDidLoad()
        UIBarButtonItem.appearance().setTitleTextAttributes(
            [
             NSAttributedString.Key.font: UIFont.systemFont(ofSize: 40),
             NSAttributedString.Key.foregroundColor: view.tintColor
            ], for: .normal)
    }

Ответы [ 4 ]

4 голосов
/ 26 марта 2019

Это не имеет ничего общего с .foregroundColor. Это имеет отношение к .tintColor и setTitleTextAttributes.

Этот параметр имеет тип [NSAttributedString.Key : Any]. Это никоим образом не рассматривает документацию для каждого ключа. Он не знает или не заботится о том, что это должно быть UIColor. Если вы передадите «squid», это скомпилируется без предупреждения (это не сработает, но скомпилирует):

UIBarButtonItem.appearance().setTitleTextAttributes(
    [
        .font: UIFont.systemFont(ofSize: 40),
        .foregroundColor: "squid",
    ], for: .normal)

Все, что он смотрит, это то, что вы присваиваете view.tintColor значение типа Any.

Проблема в том, что view.tintColor - это не UIColor, а UIColor!. На самом деле .tintColor не может быть нулем, но возможно установить в ноль:

view.tintColor        // r 0.0 g 0.478 b 1.0 a 1.0
view.tintColor = .red
view.tintColor        // r 1.0 g 0.0 b 0.0 a 1.0
view.tintColor = nil
view.tintColor        // r 0.0 g 0.478 b 1.0 a 1.0

Это имеет смысл в ObjC, но единственный способ выразить это в Swift - это использовать тип !. Когда вы назначаете ! типы другим вещам, они становятся ? типами. А это значит, что вы используете UIColor? в месте, которое принимает Any (значение словаря).

Использование необязательного значения Any может быть опасным, поскольку оно создает множество странных угловых случаев. Например, вы не можете совершать обходные действия через Any; он будет раздавлен до базового типа:

let x: Any = Optional(1)
x as? Int? // Cannot downcast from 'Any' to a more optional type 'Int?'
x as? Int  // 1

При работе с Any существует множество таких острых кромок.

Конечно, вы не имели ввиду для работы с Any. Это не твоя вина. Но вот почему Свифт жалуется.

Есть несколько решений, в зависимости от того, что вам нравится. Вы можете использовать !:

    .foregroundColor: view.tintColor!

Вы можете добавить as Any, чтобы отключить предупреждение:

    .foregroundColor: view.tintColor as Any

Лично я бы использовал as Any.

Или вы можете разработать и выгрузить значение раньше (я не рекомендую это):

let tintColor = view.tintColor ?? .blue

UIBarButtonItem.appearance().setTitleTextAttributes(
    [
        .font: UIFont.systemFont(ofSize: 40),
        .foregroundColor: tintColor,
    ], for: .normal)
3 голосов
/ 26 марта 2019

setTitleTextAttributes ожидает словарь [NSAttributedString.Key : Any]

Все может рассматриваться как Any и , поэтому это предупреждение не появляется ни в одном другом случае . Единственный раз, когда он появляется, это когда вы делаете это с Optional. Компилятор просто хочет, чтобы вы знали, что вы делаете с вашим необязательным:)

Вы спросили, почему это происходит в Xcode 10.2 и Swift 5?

Это всегда хорошо работало для опций, которые были объявлены таким образом:

let optionalNumber: Int? = 5 

и никогда для опций, которые были объявлены таким образом:

let implicitlyUnwrappedOptionalNumber: Int! = 5 

посмотрите на ваш пример: view.tintColor есть

enter image description here

Почему это не сработало для неявно развернутых опций? Потому что до Swift 5 ImplicitlyUnwrappedOptional и Optional были двух разных типов! И, как я писал ранее: он всегда хорошо работал для опциональных (и не работал для ImplicitlyUnwrappedOptional).

Сейчас они одного типа, но у неявно развернутых опционов есть специальный механизм @_autounwrapped для их различения.

Thay запущено удаление этого типа в Swift 4.2:

https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md

В этом предложении делается попытка ограничить принятие ННУ местами, где они на самом деле требуется, и положить язык Swift на пути к удаление неявно развернутых опций из системы полностью, когда другие технологии делают их ненужными. Это также полностью отменяет любое понятие IUO ниже уровня проверки типа компилятор, который существенно упростит компилятор осуществление.

но, видимо, они завершили это в Swift 5:

https://forums.swift.org/t/possible-misdiagnosis-of-se-0054/9546

ImplicitlyUnwrappedOptional больше не будет типом. Мы поместили предупреждения специально вокруг использования! потому что это легче обнаружить, но да, используя его в любом положении, которое не тип верхнего уровня переменной, параметра или возвращаемого значения устарел и будет удален. (@rudkx уже проделал большую работу для на самом деле сделать это удаление в Swift 5, некоторые из которых начнут отображаться даже в Swift 4.1.)

1 голос
/ 26 марта 2019

Просто сделайте это:

guard let viewTint = view.tintColor else { return }
NSAttributedString.Key.foregroundColor: viewTint

Надеюсь, это поможет!

0 голосов
/ 15 апреля 2019

В дополнение к тому, что Роб Нейпир написал в своем ответе , вот ответ Apple на мой отчет об ошибках:

Инжиниринг предоставил следующую информацию по этому вопросу:

Это непреднамеренный результат преднамеренного изменения в Swift 5. tintColor имеет тип UIColor !, неявно развернутый необязательный, и его нужно преобразовать в Any, чтобы его можно было добавить в словарь передано в setTitleTextAttributes (_: для :). Когда столкнулся с этим Ситуация, Swift 4.2 вставит принудительную развертку, чтобы преобразовать значение в UIColor, что вызовет сложный для отладки сбой, если значение был ноль. Swift 5.0 вместо этого преобразует значение в UIColor ?, который никогда вылетает, но выдает предупреждение при неявном преобразовании в Any.

В вашем конкретном случае свойство tintColor задокументировано, чтобы никогда вернуть ноль, так что безопасно использовать оператор распаковки писать «view.tintColor!» вместо «view.tintColor». (Это Временное решение относится к свойству tintColor - в других ситуациях где вы получаете это предупреждение, принудительное развертывание может привести к сбою приложения в во время выполнения. Только принудительное развертывание, когда вы уверены, что значение может никогда не обнуляйся.)

Если у вашего проекта есть строгое руководство по стилю, которое категорически запрещает принудительно распаковывая, вы можете вместо этого использовать оператор nil-coalescing писать что-то вроде «view.tintColor ?? UIColor.black»."

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...