Можно ли реплицировать автоматическое числовое преобразование Swifts в Foundation (NSNumber) для типов (U) Int8 / 16/32/64?

Вопрос

  • Можно ли реплицировать привязку числового значения Swifts к ссылочному типу Foundation: s NSNumber , например, UInt32 Int32 , UInt32 , Int64 и UInt64 ? В частности, повторное копирование моста с автоматическим назначением, описанного ниже.

Предполагаемый пример использования такого решения:

 let foo : Int64 = 42 let bar : NSNumber = foo /* Currently, as expected, error: cannot convert value of type 'Int64' to specified type 'NSNumber */ 

Задний план

Некоторые из родных типов (значений) типа Swift могут автоматически NSNumber с NSNumber (reference):

Экземпляры типов числовой структуры Swift, такие как Int , UInt , Float , Double и Bool , не могут быть представлены типом AnyObject , потому что AnyObject представляет только экземпляры типа classа. Однако, когда включено мостовое подключение к Foundation , переменные Swift могут быть назначены константам и переменным типа AnyObject качестве мостовых экземпляров classа NSNumber .

Swift автоматически соединяет определенные типы номеров, такие как Int и Float , с NSNumber . Этот мост позволяет создавать NSNumber из одного из следующих типов:

 let n = 42 let m: NSNumber = n 

Он также позволяет передавать значение типа Int , например, в аргумент, ожидающий NSNumber . …

Все следующие типы автоматически соединяются с NSNumber:

 - Int - UInt - Float - Double - Bool 

От совместимости – Работа с типами данных cocoa – Числа .

Итак, зачем пытаться реплицировать это для типов IntXX / UIntXX ?

В первую очередь: любопытство, вызванное недавним рассмотрением некоторых вопросов, лежащих в основе проблем, связанных с путаницей в том, почему тип значения Int видимому, может быть представлен переменной AnyObject (reference), тогда как, например, Int64 , не может; что, естественно, объясняется описанным выше мостиком. Чтобы выбрать несколько:

  • Почему Swift Array совместим с AnyObject?
  • Нельзя индексировать значение типа ‘[UInt32]’
  • Использование обобщенных массивов в быстрых

Однако ни один из вопросов и ответов: s выше не упоминает о возможности фактического внедрения такого автоматического AnyObject с AnyObject ( NSNumber ) из NSNumber типов Int64 , UInt16 и т. Д. Ответы в этих streamах скорее фокусируются (правильно) на объяснении того, почему AnyObject не может хранить типы значений и как IntXX / UIntXX не соединяются для автоматического преобразования в базовые типы Foundation.

Вторично: для приложений, работающих как на 32-битной, так и на 64-битной архитектурах, есть некоторые узкие варианты использования – использование типов родных номеров Swift, неявно преобразованных в AnyObject , в некотором контексте, где использование Int32 или Int64 типа было бы предпочтительнее Int . Один (несколько) такой пример:

  • Почему этот случайный код функции падает на iPhone 5 и 5S.

Да (возможно): по протоколу _ObjectiveCBridgeable

(Следующий ответ основан на использовании Swift 2.2 и XCode 7.3.)

Так же, как я размышлял над тем, отправлять или просто пропустить этот вопрос, я наткнулся на swift/stdlib/public/core/BridgeObjectiveC.swift в исходном коде Swift, в частности на протокол _ObjectiveCBridgeable . Я кратко заметил протокол ранее на Swiftdoc.org , но в его текущей (пустой) форме плана в последнем, я никогда не думал об этом. Используя чертежи для _ObjectiveCBridgeable из источника Swift, мы можем, однако, быстро разрешить некоторым из них пользовательский тип.

Прежде чем продолжить, обратите внимание, что _ObjectiveCBridgeable является внутренним / скрытым протоколом ( _UnderScorePreFixedProtocol ), поэтому решения, основанные на нем, могут прерываться без предупреждения в будущих версиях Swift.


Включение моста Int64 для classа Foundation NSNumber

В качестве примера, расширьте Int64 чтобы он соответствовал _ObjectiveCBridgeable , и затем проверьте, достаточно ли этого достаточно простого исправления для неявного преобразования типа (моста) из Int64 в class NSNumber Foundation.

 import Foundation extension Int64: _ObjectiveCBridgeable { public typealias _ObjectiveCType = NSNumber public static func _isBridgedToObjectiveC() -> Bool { return true } public static func _getObjectiveCType() -> Any.Type { return _ObjectiveCType.self } public func _bridgeToObjectiveC() -> _ObjectiveCType { return NSNumber(longLong: self) } public static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Int64?) { result = source.longLongValue } public static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Int64?) -> Bool { self._forceBridgeFromObjectiveC(source, result: &result) return true } } 

Контрольная работа:

 /* Test case: scalar */ let fooInt: Int = 42 let fooInt64: Int64 = 42 var fooAnyObj : AnyObject fooAnyObj = fooInt // OK, natively fooAnyObj = fooInt64 // OK! _ObjectiveCBridgeable conformance successful /* Test case: array */ let fooIntArr: [Int] = [42, 23] let fooInt64Arr: [Int64] = [42, 23] var fooAnyObjArr : [AnyObject] fooAnyObjArr = fooIntArr // OK, natively fooAnyObjArr = fooInt64Arr // OK! _ObjectiveCBridgeable conformance successful 

Следовательно, соответствие _ObjectiveCBridgeable действительно достаточно, чтобы обеспечить автоматическое _ObjectiveCBridgeable по назначению соответствующему classу Foundation; в этом случае NSNumber (в Swift, __NSCFNumber ).


Включение Int8 , UInt8 , Int16 , UInt16 , Int32 , UInt32 , ( Int64 ) и UInt64 соединяющих NSNumber

Вышеприведенное соответствие Int64 to _ObjectiveCBridgeable может быть легко изменено для охвата любого из целых типов Swift-native, используя приведенную ниже таблицу преобразования NSNumber .

 /* NSNumber initializer: NSNumber native Swift type property -------------------------------- ----------------------------------- init(char: ) .charValue init(unsignedChar: ) .unsignedCharValue init(short: ) .shortValue init(unsignedShort: ) .unsignedShortValue init(int: ) .intValue init(unsignedInt: ) .unsignedIntValue init(longLong: ) .longLongValue init(unsignedLongLong: ) .unsignedLongLongValue */ 
  • Быстрые расширения протоколов
  • Swift 2 (executeFetchRequest): обработка ошибок
  • Вернуть тип instancetype в Swift
  • Расширять типы массивов, используя предложение where в Swift
  • .toInt () удален в Swift 2?
  • Swift 2.0: «enumerate» недоступен: вызовите метод «enumerate ()» в последовательности
  • Операторы «++» и «-» устарели Xcode 7.3
  • Переопределение методов в расширениях Swift
  • попробуйте, попробуйте! & пытаться? какая разница, и когда использовать их?
  • Swift 2 - UnsafeMutablePointer для объекта
  • Давайте будем гением компьютера.