Swift 3.0 - 损坏的 func 值(对于组件:Calendar.Component) ->内部? [英] Swift 3.0 - Broken func value(for component: Calendar.Component) -> Int?

查看:15
本文介绍了Swift 3.0 - 损坏的 func 值(对于组件:Calendar.Component) ->内部?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有解决似乎已损坏的值(对于组件:Calendar.Component)的方法?还是动态调用属性版本?

func dateComponentsValueShouldBeNil() {让 dateComponents = DateComponents(month: 3)debugPrint("Month", dateComponents.month)//"Month" Optional(3)debugPrint("Property", dateComponents.hour)//"Property" nildebugPrint("Enumeration", dateComponents.value(for: .hour))//"Enumeration" Optional(9223372036854775807)}

解决方案

DateComponents 实例中的非定义日期组件(值 nil 那里)在包装NSDateComponents 实例由全局 int 属性 NSDateComponentUndefined

这不是一个错误/损坏的方法,而是根据 DateComponentsNSDateComponents(它派生自 NSObject: 不使用可选项和 nil 来指定没有值的对象).具体来说,前者的 value(...) 方法主要是后者的 value(forComponent:) 方法(API 参考:Foundation -> NSDateComponents)

<块引用>

value(forComponent:)

返回给定 NSCalendarUnit 值的值.

声明

func value(forComponent unit: NSCalendar.Unit) ->整数

此方法不能返回 nil,但通过 全局 int 变量 NSDateComponentUndefined.

让 dateComponents = DateComponents(month: 3)debugPrint("Enumeration", dateComponents.value(for: .hour))//"枚举" 可选(9223372036854775807)debugPrint("NSDateComponentUndefined", NSDateComponentUndefined)//"NSDateComponentUndefined" 9223372036854775807

API 参考:Foundation -> NSDateComponents 我们读到:

<块引用>

...

NSDateComponents 对象不需要定义所有组件领域.当 NSDateComponents 的新实例被创建时,日期组件设置为 NSDateComponentUndefined.

因此,尝试为尚未调用的 DateComponentsCalendar.Component 成员调用 value(...) 的返回初始化不是乱码,而是默认的未定义值 NSDateComponentUndefined(一个全局 int 属性,它发生返回/被设置为 Int64.max = 9223372036854775807).

<小时>

为了更深入地了解这方面的细节,我们可以访问 DateComponents 的源代码(swift-corelibs-foundation/Foundation/DateComponents.swift)

///设置属性之一的值,使用枚举值而不是属性名称.//////日历、timeZone 和 isLeapMonth 属性不能通过此方法设置.public mutating func setValue(_ value: Int?, for component: Calendar.Component) {_applyMutation {$0.setValue(_setter(value), forComponent: Calendar._toCalendarUnit([component]))}}///使用枚举值而不是属性名称返回属性之一的值.//////日历和 timeZone 以及 isLeapMonth 属性值无法通过此方法检索.公共函数值(对于组件:Calendar.Component)->内部?{返回_handle.map {$0.value(forComponent: Calendar._toCalendarUnit([component]))}}

property _handle 上面包裹了 NSDateComponents

internal var _handle: _MutableHandle

_MutableHandle (swift-corelibs-foundation/Foundation/Boxing.swift)

内部最终类_MutableHandle其中 MutableType : NSCopying {fileprivate var _pointer : MutableType//...///对引用类型应用闭包.func map(_ whatToDo : (MutableType) throws -> ReturnType) rethrows ->返回类型{返回尝试 whatToDo(_pointer)}//...}

从上面ReturnTypevalue(...)的签名推断为Int?_toCalendarValue 定义为 (swift-corelibs-foundation/Foundation/Calendar.swift)

internal static func _toCalendarUnit(_units: Set) ->NSCalendar.Unit {让 unitMap: [组件 : NSCalendar.Unit] =[.era: .era,.year: .year,.月:.月,.day: .day,.小时:.小时,.分钟:.分钟,.second: .second,.weekday: .weekday,.weekdayOrdinal: .weekdayOrdinal,.季:.季,.weekOfMonth: .weekOfMonth,.weekOfYear: .weekOfYear,.yearForWeekOfYear: .yearForWeekOfYear,.纳秒:.纳秒,.calendar: .calendar,.timeZone: .timeZone]var 结果 = NSCalendar.Unit()对于 u 单位 {让 _ = result.insert(unitMap[u]!)}返回结果}

因此,value(...) 返回的主体中的 whatToDo 可以被解读为等效于对

的调用

NSDateComponents.value(forComponent: NSCalendar.Unit)

正如本答案顶部所述,此调用永远不会返回 nil(返回类型 Int).

如果我们最终回到的源头DateComponents,我们看到下面的私有 getter 和 setter 处理了 NSDateComponentUndefinednil 之间的桥接".

////从 NSDateComponentUndefined 值转换为适当的 Swift 可选私有函数 _getter(_ x : Int) ->内部?{ 返回 x == NSDateComponentUndefined ?零:x }///从正确的 Swift 可选值转换为 NSDateComponentUndefinedprivate func _setter(_ x : Int?) ->Int { if let xx = x { return xx } else { return NSDateComponentUndefined } }

Is there a workaround for value(for component: Calendar.Component) seemingly being broken? Or a dynamic way to call the property version?

func dateComponentsValueShouldBeNil() {
     let dateComponents = DateComponents(month: 3)
     debugPrint("Month", dateComponents.month) // "Month" Optional(3)
     debugPrint("Property", dateComponents.hour) // "Property" nil
     debugPrint("Enumeration", dateComponents.value(for: .hour)) // "Enumeration" Optional(9223372036854775807)
}

解决方案

Non-defined date components in a DateComponents instance (valued nil there) are represented in the wrapped NSDateComponents instance by the global int property NSDateComponentUndefined

This is not a bug/broken method, but follows from the fact that DateComponents is tighly connected to NSDateComponents (which derives from NSObject: not using optionals an nil to specify objects with no value). Specifically, the former's value(...) method is, principally, a wrapper for the latter's value(forComponent:) method (API Reference: Foundation -> NSDateComponents)

value(forComponent:)

Returns the value for a given NSCalendarUnit value.

Declaration

func value(forComponent unit: NSCalendar.Unit) -> Int

This method cannot return nil, but represents date components without a value by the global int variable NSDateComponentUndefined.

let dateComponents = DateComponents(month: 3)
debugPrint("Enumeration", dateComponents.value(for: .hour))
    // "Enumeration" Optional(9223372036854775807)
debugPrint("NSDateComponentUndefined", NSDateComponentUndefined)
    // "NSDateComponentUndefined" 9223372036854775807

From API Reference: Foundation -> NSDateComponents we read:

...

An NSDateComponents object is not required to define all the component fields. When a new instance of NSDateComponents is created the date components are set to NSDateComponentUndefined.

Hence, the return for attempting to call value(...) for a Calendar.Component member of DateComponents that has not been initialized is not gibberish, but the default undefined value NSDateComponentUndefined (a global int property which happens return/be set to Int64.max = 9223372036854775807).


To dwell deeper into the details of this, we may visit the source of DateComponents (swift-corelibs-foundation/Foundation/DateComponents.swift)

/// Set the value of one of the properties, using an enumeration value instead of a property name.
///
/// The calendar and timeZone and isLeapMonth properties cannot be set by this method.
public mutating func setValue(_ value: Int?, for component: Calendar.Component) {
    _applyMutation {
        $0.setValue(_setter(value), forComponent: Calendar._toCalendarUnit([component]))
    }
}

/// Returns the value of one of the properties, using an enumeration value instead of a property name.
///
/// The calendar and timeZone and isLeapMonth property values cannot be retrieved by this method.
public func value(for component: Calendar.Component) -> Int? {
    return _handle.map {
        $0.value(forComponent: Calendar._toCalendarUnit([component]))
    }
}

property _handle above wraps NSDateComponents

internal var _handle: _MutableHandle<NSDateComponents>

in a _MutableHandle (swift-corelibs-foundation/Foundation/Boxing.swift)

internal final class _MutableHandle<MutableType : NSObject> where MutableType : NSCopying {
    fileprivate var _pointer : MutableType

    // ...

    /// Apply a closure to the reference type.
    func map<ReturnType>(_ whatToDo : (MutableType) throws -> ReturnType) rethrows -> ReturnType {
        return try whatToDo(_pointer)
    }

    // ...
}

From the signature of value(...) above ReturnType is inferred to as Int?, and _toCalendarValue is defined as (swift-corelibs-foundation/Foundation/Calendar.swift)

internal static func _toCalendarUnit(_ units: Set<Component>) -> NSCalendar.Unit {
    let unitMap: [Component : NSCalendar.Unit] =
        [.era: .era,
         .year: .year,
         .month: .month,
         .day: .day,
         .hour: .hour,
         .minute: .minute,
         .second: .second,
         .weekday: .weekday,
         .weekdayOrdinal: .weekdayOrdinal,
         .quarter: .quarter,
         .weekOfMonth: .weekOfMonth,
         .weekOfYear: .weekOfYear,
         .yearForWeekOfYear: .yearForWeekOfYear,
         .nanosecond: .nanosecond,
         .calendar: .calendar,
         .timeZone: .timeZone]

    var result = NSCalendar.Unit()
    for u in units {
        let _ = result.insert(unitMap[u]!)
    }
    return result
}

Hence, whatToDo in the body of the return of value(...) can be deciphered to be equivalent to a call to

NSDateComponents.value(forComponent: NSCalendar.Unit)

And as descriped in the top of this answer, this call can never return nil (return type Int).

If we, finally, return to the source of DateComponents, we see that the following private getter and setter handles the "bridging" between NSDateComponentUndefined and nil.

/// Translate from the NSDateComponentUndefined value into a proper Swift optional
private func _getter(_ x : Int) -> Int? { return x == NSDateComponentUndefined ? nil : x }

/// Translate from the proper Swift optional value into an NSDateComponentUndefined
private func _setter(_ x : Int?) -> Int { if let xx = x { return xx } else { return NSDateComponentUndefined } }

这篇关于Swift 3.0 - 损坏的 func 值(对于组件:Calendar.Component) ->内部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆