发现困惑

在整理 [[『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 符合ExpressibleByBooleanLiteralExpressibleByFloatLiteral 和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.

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计