In Swift, how is it that AnyObject
supports subscripts, even for types that are't subscriptable? Example:
在Swift中,AnyObject如何支持下标,即使对于不可订阅的类型也是如此?例:
let numbers: AnyObject = [11, 22, 33]
numbers[0] // returns 11
let prices: AnyObject = ["Bread": 3.49, "Pencil": 0.5]
prices["Bread"] // returns 3.49
let number: AnyObject = 5
number[0] // return nil
let number: AnyObject = Int(5)
number[0] // return nil
Yet if my number
is declared as Int
then it's a syntax error:
然而,如果我的数字被声明为Int,那么这是一个语法错误:
let number: Int = 5
number[0] // won't compile
Interestingly, Any
doesn't have subscript support.
有趣的是,Any没有下标支持。
2 个解决方案
#1
12
This works only if you import Foundation
, as Swift is doing in that case some bridging to Objective-C
types - a NSArray
-like object in this case.
这只有在你导入Foundation时才有效,因为在这种情况下Swift正在做一些桥接到Objective-C类型 - 在这种情况下类似于NSArray的对象。
import Foundation
let numbers: AnyObject = [11, 22, 33]
numbers.dynamicType //_SwiftDeferredNSArray.Type
If you don't import Foundation
, then you are not even allowed to make the assignment (because a Swift array is a struct and not an object).
如果不导入Foundation,则甚至不允许进行赋值(因为Swift数组是结构而不是对象)。
let numbers: AnyObject = [11, 22, 33] // error: contextual type 'AnyObject' cannot be used with array literal
You can cast to Any
, though:
但是你可以强制转换为Any:
let numbers: Any = [11, 22, 33]
numbers.dynamicType // Array<Int>.Type
Why does the import Foundation
does the trick? This is documented in the AnyObject
type description:
为什么导入基金会会这样做?这在AnyObject类型描述中有记录:
/// When used as a concrete type, all known `@objc` methods and
/// properties are available, as implicitly-unwrapped-optional methods
/// and properties respectively, on each instance of `AnyObject`. For
/// example:
///
/// class C {
/// @objc func getCValue() -> Int { return 42 }
/// }
///
/// // If x has a method @objc getValue()->Int, call it and
/// // return the result. Otherwise, return nil.
This means you can even call methods on your array that don't necessarily exist on NSArray
, but exists in the Objective-C
world, like for example:
这意味着你甚至可以在数组上调用NSArray上不一定存在的方法,但是存在于Objective-C世界中,例如:
numbers.lowercaseString // nil
and Swift will gracefully return you a nil
value instead of throwing you a nasty object does not recognises selector
exception, like it would happen in Objective-C. If this is good or bad, remains to debate :)
并且Swift将优雅地返回一个nil值,而不是抛弃一个讨厌的对象,不会识别选择器异常,就像它会在Objective-C中发生一样。如果这是好还是坏,仍然有争议:)
Update The above seems to work only for properties, and property-like methods, if you try to use an Objective-C method, then you'll run into the unrecognized selector issue:
更新以上似乎仅适用于属性和类似属性的方法,如果您尝试使用Objective-C方法,那么您将遇到无法识别的选择器问题:
import Foundation
@objc class TestClass: NSObject {
@objc var someProperty: Int = 20
@objc func someMethod() {}
}
let numbers: AnyObject = [11, 22, 33]
numbers.lowercaseString // nil
numbers.someMethod // nil
numbers.someMethod() // unrecognized selector
numbers.stringByAppendingString("abc") // unrecognized selector
#2
5
It has to do with the bridging of types when assigning a value to an object of type AnyObject
:
在为AnyObject类型的对象赋值时,它与类型的桥接有关:
let numbers: AnyObject = [11, 22, 33]
print(numbers.dynamicType) // _SwiftDeferredNSArray.Type
let prices: AnyObject = ["Bread": 3.49, "Pencil": 0.5]
print(prices.dynamicType) // _NativeDictionaryStorageOwner<String, Double>.Type
let number: AnyObject = 5
print(number.dynamicType) // __NSCFNumber.Type
let anotherNumber: Int = 5
print(anotherNumber.dynamicType) // Int.Type
Behind the scenes, _SwiftDeferredNSArray.Type
, _NativeDictionaryStorageOwner<String, Double>.Type
, and __NSCFNumber.Type
must support subscripts while Int.Type
does not.
在幕后,_SwiftDeferredNSArray.Type,_NativeDictionaryStorageOwner
This is assuming you have imported Foundation. For an explanation with pure Swift types, see Cristik's answer.
这假设您已导入Foundation。有关纯Swift类型的解释,请参阅Cristik的答案。
#1
12
This works only if you import Foundation
, as Swift is doing in that case some bridging to Objective-C
types - a NSArray
-like object in this case.
这只有在你导入Foundation时才有效,因为在这种情况下Swift正在做一些桥接到Objective-C类型 - 在这种情况下类似于NSArray的对象。
import Foundation
let numbers: AnyObject = [11, 22, 33]
numbers.dynamicType //_SwiftDeferredNSArray.Type
If you don't import Foundation
, then you are not even allowed to make the assignment (because a Swift array is a struct and not an object).
如果不导入Foundation,则甚至不允许进行赋值(因为Swift数组是结构而不是对象)。
let numbers: AnyObject = [11, 22, 33] // error: contextual type 'AnyObject' cannot be used with array literal
You can cast to Any
, though:
但是你可以强制转换为Any:
let numbers: Any = [11, 22, 33]
numbers.dynamicType // Array<Int>.Type
Why does the import Foundation
does the trick? This is documented in the AnyObject
type description:
为什么导入基金会会这样做?这在AnyObject类型描述中有记录:
/// When used as a concrete type, all known `@objc` methods and
/// properties are available, as implicitly-unwrapped-optional methods
/// and properties respectively, on each instance of `AnyObject`. For
/// example:
///
/// class C {
/// @objc func getCValue() -> Int { return 42 }
/// }
///
/// // If x has a method @objc getValue()->Int, call it and
/// // return the result. Otherwise, return nil.
This means you can even call methods on your array that don't necessarily exist on NSArray
, but exists in the Objective-C
world, like for example:
这意味着你甚至可以在数组上调用NSArray上不一定存在的方法,但是存在于Objective-C世界中,例如:
numbers.lowercaseString // nil
and Swift will gracefully return you a nil
value instead of throwing you a nasty object does not recognises selector
exception, like it would happen in Objective-C. If this is good or bad, remains to debate :)
并且Swift将优雅地返回一个nil值,而不是抛弃一个讨厌的对象,不会识别选择器异常,就像它会在Objective-C中发生一样。如果这是好还是坏,仍然有争议:)
Update The above seems to work only for properties, and property-like methods, if you try to use an Objective-C method, then you'll run into the unrecognized selector issue:
更新以上似乎仅适用于属性和类似属性的方法,如果您尝试使用Objective-C方法,那么您将遇到无法识别的选择器问题:
import Foundation
@objc class TestClass: NSObject {
@objc var someProperty: Int = 20
@objc func someMethod() {}
}
let numbers: AnyObject = [11, 22, 33]
numbers.lowercaseString // nil
numbers.someMethod // nil
numbers.someMethod() // unrecognized selector
numbers.stringByAppendingString("abc") // unrecognized selector
#2
5
It has to do with the bridging of types when assigning a value to an object of type AnyObject
:
在为AnyObject类型的对象赋值时,它与类型的桥接有关:
let numbers: AnyObject = [11, 22, 33]
print(numbers.dynamicType) // _SwiftDeferredNSArray.Type
let prices: AnyObject = ["Bread": 3.49, "Pencil": 0.5]
print(prices.dynamicType) // _NativeDictionaryStorageOwner<String, Double>.Type
let number: AnyObject = 5
print(number.dynamicType) // __NSCFNumber.Type
let anotherNumber: Int = 5
print(anotherNumber.dynamicType) // Int.Type
Behind the scenes, _SwiftDeferredNSArray.Type
, _NativeDictionaryStorageOwner<String, Double>.Type
, and __NSCFNumber.Type
must support subscripts while Int.Type
does not.
在幕后,_SwiftDeferredNSArray.Type,_NativeDictionaryStorageOwner
This is assuming you have imported Foundation. For an explanation with pure Swift types, see Cristik's answer.
这假设您已导入Foundation。有关纯Swift类型的解释,请参阅Cristik的答案。