В значении Any хранится NSNumber: почему условительное приведение к Int может успешно завершиться, хотя исходный объект не является экземпляром Swift Int?
Условительное приведение к Int может быть успешным благодаря мостированию Foundation между NSNumber и числовыми типами Swift. Это не обычное приведение по идентичности динамического типа, а специальное преобразование, учитывающее представимое числовое значение.
Foundation обеспечивает взаимодействие Swift с Objective-C, где числовые значения часто представлены единым ссылочным классом NSNumber. В Swift такие значения обычно выражаются конкретными типами вроде Int, Double или Bool, поэтому среда выполнения должна уметь преобразовывать некоторые объекты Foundation в соответствующие Swift-значения.
Статический тип Any не сообщает, что именно находится внутри контейнера. При приведении к Int Swift проверяет не только точное совпадение динамического типа, но и допустимые мосты между типами.
Нельзя, однако, считать такое приведение универсальным числовым преобразованием. Например, произвольное значение Double из Any не обязано успешно приводиться к Int: обычный динамический cast не равен операции округления или усечения.
NSNumber — объект Foundation, способный представлять различные числовые значения. При проверке as? Int Swift и Foundation могут распознать числовое содержимое NSNumber, проверить его совместимость с Int и вернуть значение Swift-типа.
В этом примере integer имеет тип Int?, а его значение — some(42). Внешний Optional появляется потому, что as? всегда описывает возможность неуспешного приведения.
Важно отличать три ситуации: точное совпадение типов, мостирование Foundation и произвольное вычислительное преобразование. NSNumber может быть мостирован к подходящему числовому типу, но as? не следует воспринимать как замену Int(...), Double(...) или явной проверке диапазона.
Результат также зависит от того, можно ли безопасно представить числовое содержимое в целевом типе. Поэтому код, которому важны точность, переполнение или дробная часть, должен явно задавать правила преобразования, а не полагаться только на условительный cast.
Мобильное приложение получает значения из Objective-C SDK в виде Any. Числовое поле иногда приходит как Swift-значение, а иногда как NSNumber.
Вариант с безусловным as! Int прост, но аварийно завершит работу при неожиданном формате или неподходящем диапазоне. Вариант с игнорированием мостирования и ручным разбором всех вариантов усложняет код и дублирует возможности Foundation.
Практичное решение — использовать as? Int, обработать отсутствие результата и отдельно определить политику для дробных или потенциально переполняющихся значений. Это сохраняет безопасность выполнения, учитывает мостирование и не скрывает бизнес-правила преобразования.
1. Вопрос: Является ли успешное приведение NSNumber к Int доказательством того, что динамический тип объекта равен Int?
Ответ: Нет. Успех может быть следствием мостирования, а не идентичности типов. Объект по-прежнему может быть экземпляром NSNumber, тогда как результат cast — отдельное значение Swift-типа Int.
2. Вопрос: Преобразует ли as? Int любое числовое значение, например дробное, с автоматическим усечением?
Ответ: Нет. as? проверяет допустимость динамического приведения и мостирования, но не задаёт произвольное правило округления или усечения. Если требуется конкретная политика преобразования Double в Int, её нужно выразить явно.
3. Вопрос: Что произойдёт, если NSNumber содержит значение, не представимое в Int на данной платформе?
Ответ: Условительное приведение может вернуть nil, поскольку безопасный результат целевого типа получить нельзя. Это одна из причин предпочитать as? вместо as!: отказ преобразования становится обычным значением, а не аварийным завершением программы.