发现困惑
在整理 [[『Core Animation』CAKeyframeAnimation实战之心跳+雷达]] 中的 [[『Core Animation』CAKeyframeAnimation实战之心跳+雷达#keyTimes
|keyTimes]] 时,发现 keyTimes
是 [NSNumber]?
类型的,但是项目中代码却是 Float
类型数组(如下代码),编译、运行竟都没有报错,Why
?
1
|
keyframeAnimation.keyTimes = [0, 0.25, 0.55, 0.8, 1.0]
|
查找答案
搜索 swift nsnumber ,直到看到 为什么数字文字可以解释为Swift中的NSNumber? 中的回答:
NSNumber 符合ExpressibleByBooleanLiteral,ExpressibleByFloatLiteral 和ExpressibleByIntegerLiteral 协议,这意味着它可以 从布尔值,浮点或整数文字初始化:
1
2
3
|
let n1: NSNumber = false
let n2: NSNumber = 12.34
let n3: NSNumber = 123
|
虽然答案是找到了,但这个搜索结果显然不是源地址,所以就去 Stack Overflow 上搜了一下 ExpressibleByIntegerLiteral
,找到了源地址:Why can a numeric literal be interpreted as an NSNumber in Swift?
验证答案
extension NSNumber
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
extension NSNumber : ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral, ExpressibleByBooleanLiteral {
/// Create an instance initialized to `value`.
@nonobjc required public convenience init(integerLiteral value: Int)
/// Create an instance initialized to `value`.
@nonobjc required public convenience init(floatLiteral value: Double)
/// Create an instance initialized to `value`.
@nonobjc required public convenience init(booleanLiteral value: Bool)
/// A type that represents a Boolean literal, such as `Bool`.
public typealias BooleanLiteralType = Bool
/// A type that represents a floating-point literal.
///
/// Valid types for `FloatLiteralType` are `Float`, `Double`, and `Float80`
/// where available.
public typealias FloatLiteralType = Double
/// A type that represents an integer literal.
///
/// The standard library integer and floating-point types are all valid types
/// for `IntegerLiteralType`.
public typealias IntegerLiteralType = Int
}
|
ExpressibleByFloatLiteral
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/// A type that can be initialized with a floating-point literal.
///
/// The standard library floating-point types---`Float`, `Double`, and
/// `Float80` where available---all conform to the `ExpressibleByFloatLiteral`
/// protocol. You can initialize a variable or constant of any of these types
/// by assigning a floating-point literal.
///
/// // Type inferred as 'Double'
/// let threshold = 6.0
///
/// // An array of 'Double'
/// let measurements = [2.2, 4.1, 3.65, 4.2, 9.1]
///
/// Conforming to ExpressibleByFloatLiteral
/// =======================================
///
/// To add `ExpressibleByFloatLiteral` conformance to your custom type,
/// implement the required initializer.
public protocol ExpressibleByFloatLiteral {
/// A type that represents a floating-point literal.
///
/// Valid types for `FloatLiteralType` are `Float`, `Double`, and `Float80`
/// where available.
associatedtype FloatLiteralType : _ExpressibleByBuiltinFloatLiteral
/// Creates an instance initialized to the specified floating-point value.
///
/// Do not call this initializer directly. Instead, initialize a variable or
/// constant using a floating-point literal. For example:
///
/// let x = 21.5
///
/// In this example, the assignment to the `x` constant calls this
/// floating-point literal initializer behind the scenes.
///
/// - Parameter value: The value to create.
init(floatLiteral value: Self.FloatLiteralType)
}
|
最后
虽然知道了答案,但是对于 ExpressibleByFloatLiteral
的理解还是很迷糊,于是又看了一下 Swift ExpressibleByIntegerLiteral - How exactly does it work? ,似乎才明白那么一些:
It’s compiler magic, so unfortunately you cannot declare such a protocol yourself.