Swift 3.0 - 损坏的 func 值(对于组件:Calendar.Component) ->内部? [英] Swift 3.0 - Broken func value(for component: Calendar.Component) -> Int?
问题描述
是否有解决似乎已损坏的值(对于组件: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
这不是一个错误/损坏的方法,而是根据 DateComponents
与 NSDateComponents
(它派生自 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
.
因此,尝试为尚未调用的 DateComponents
的 Calendar.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)}//...}
从上面ReturnType
的value(...)
的签名推断为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 处理了 NSDateComponentUndefined
和 nil
之间的桥接".
////从 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 ofNSDateComponents
is created the date components are set toNSDateComponentUndefined
.
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屋!