Существует ли правильный способ определить, что NSNumber является производным от Bool с помощью Swift?
NSNumber, содержащий Bool, легко спутать с другими типами, которые могут быть обернуты в класс NSNumber:
NSNumber(bool:true).boolValue // true
NSNumber(integer: 1).boolValue // true
NSNumber(integer: 1) as? Bool // true
NSNumber(bool:true) as? Int // 1
NSNumber(bool:true).isEqualToNumber(1) // true
NSNumber(integer: 1).isEqualToNumber(true) // true
Однако информация о его первоначальном типе сохраняется, как мы видим здесь:
NSNumber(bool:true).objCType.memory == 99 // true
NSNumber(bool:true).dynamicType.className() == "__NSCFBoolean" // true
NSNumber(bool:true).isEqualToValue(true) || NSNumber(bool:true).isEqualToValue(false) //true
Вопрос в том, какой из этих подходов является лучшим (и / или самым безопасным) для определения того, когда Bool был завернут в NSN-число, а не что-то другое? Все ли они одинаково действительны? Или есть другое, лучшее решение?3 ответа:
Вы можете задать тот же вопрос для Objective-C, и вот ответ в Objective-C, который вы можете вызвать или перевести в Swift.
NSNumberявляется бесплатным мостом кCFNumberRef, что является еще одним способом сказать, что объектNSNumberна самом деле является объектомCFNumber(и наоборот). ТеперьCFNumberRefимеет определенный тип для булевых чисел,CFBooleanRef, и это используется при создании булевогоCFNumberRefakaNSNumber *... Поэтому все, что вам нужно сделать, это проверить, является ли вашNSNumber *экземпляромCFBooleanRef:- (BOOL) isBoolNumber:(NSNumber *)num { CFTypeID boolID = CFBooleanGetTypeID(); // the type ID of CFBoolean CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num)); // the type ID of num return numID == boolID; }Примечание: Вы можете заметить, что
NSNumber/CFNumberобъекты, созданные из булевых символов, на самом деле являются предопределенными постоянными объектами; один дляYES, один дляNO. У вас может возникнуть искушение положиться на это для идентификации. Однако, хотя в настоящее время это, по-видимому, верно и показано в исходном коде Apple, насколько нам известно, это не документировано, поэтому не следует полагаться.HTH
Добавление
Swift код перевод (по GoodbyeStackOverflow):
func isBoolNumber(num:NSNumber) -> Bool { let boolID = CFBooleanGetTypeID() // the type ID of CFBoolean let numID = CFGetTypeID(num) // the type ID of num return numID == boolID }
Первый из них является правильным.
NSNumberэто класс Objective-C. Он построен для Objective-C. Он хранит тип, используя кодировку типа Objective-C. Поэтому в Objective-C лучшим решением было бы:number.objCType[0] == @encoding(BOOL)[0] // or string compare, what is not necessary hereЭто гарантирует, что изменение кодировки типа будет работать после повторной компиляции.
AFAIK у вас нет
@encoding()в Swift. Поэтому вы должны использовать буквальное выражение. Однако это не приведет к разрыву, так как@encoding()заменяется во время компиляции и изменение кодировок приведет к тому, что разрыв с компилированным кодом. Вряд ли.Второй подход использует внутренний идентификатор. Это, вероятно, подлежит изменению.
Я думаю, что третий подход будет иметь ложные срабатывания.
Не полагайтесь на имя класса, так как оно, скорее всего, принадлежит кластеру классов и является деталью реализации (и поэтому может быть изменено).
К сожалению, тип Objective-CBOOLизначально был просто typedef дляsigned charв C, который всегда кодируется какc(это значение99, которое вы видите, так какcв ASCII равно 99).В современном Objective-C я считаю, что тип
BOOLявляется фактическим Булевым типом (т. е. больше не просто typedef дляsigned char), а для совместимость, он все еще кодирует какc, Когда дано@encode().Таким образом, нет никакого способа сказать, относится ли
Возможно, если вы объясните, почему вам нужно знать, был ли99первоначально кsigned charили кBOOL, посколькуNSNumberотносится к одному и тому же.NSNumberизначальноBOOL, может быть, есть лучшее решение.