是否存在针对值(对于组件:Calendar.Component)而言似乎已损坏的解决方法?还是动态调用属性版本的方法?
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)
}
Run Code Online (Sandbox Code Playgroud)
DateComponents实例中的未定义日期成分(在nil此处有值)在包装的NSDateComponents实例中由global int属性表示NSDateComponentUndefined这不是错误/无效的方法,而是DateComponents基于紧密连接的事实NSDateComponents(它源自NSObject:不使用optionals nil指定没有值的对象)。具体来说,前者的value(...)方法主要是后者value(forComponent:)方法的包装器(API参考:Foundation-> NSDateComponents)
Run Code Online (Sandbox Code Playgroud)value(forComponent:)返回给定NSCalendarUnit值的值。
宣言
Run Code Online (Sandbox Code Playgroud)func value(forComponent unit: NSCalendar.Unit) -> Int
此方法不能返回nil,但是通过全局int变量NSDateComponentUndefined表示没有值的日期分量。
let dateComponents = DateComponents(month: 3)
debugPrint("Enumeration", dateComponents.value(for: .hour))
// "Enumeration" Optional(9223372036854775807)
debugPrint("NSDateComponentUndefined", NSDateComponentUndefined)
// "NSDateComponentUndefined" 9223372036854775807
Run Code Online (Sandbox Code Playgroud)
从API参考:Foundation-> NSDateComponents中,我们读取:
...
一个
NSDateComponents对象不要求定义所有组件字段。NSDateComponents创建的新实例时,日期组件将设置为NSDateComponentUndefined。
因此,尝试调用尚未初始化value(...)的Calendar.Component成员的返回DateComponents不是乱码,而是默认的未定义值NSDateComponentUndefined(int发生在return /处为的全局属性Int64.max = 9223372036854775807)。
为了更深入地了解这一点,我们可以访问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]))
}
}
Run Code Online (Sandbox Code Playgroud)
_handle包装上的属性NSDateComponents
internal var _handle: _MutableHandle<NSDateComponents>
Run Code Online (Sandbox Code Playgroud)
在_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)
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
从value(...)上面的签名ReturnType推断为Int?,并将_toCalendarValue其定义为(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
}
Run Code Online (Sandbox Code Playgroud)
因此,whatToDo在的返回正文中,value(...)可以解读为等效于
NSDateComponents.value(forComponent: NSCalendar.Unit)
Run Code Online (Sandbox Code Playgroud)
而且,如该答案顶部所述,此调用将永远不会返回nil(返回类型Int)。
如果最后返回到的源DateComponents,我们将看到以下私有获取器和设置器处理了NSDateComponentUndefined和之间的“桥接” 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 } }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
708 次 |
| 最近记录: |