NSDateから年・月・日などの数字だけを抜き出すときにNSDateComonentsを使うんだけど、Swiftでちょっと書き方が変わった部分がある。
Objective-C時代はこんな書き方でした。リファレンスからの抜粋。
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDate *date = [NSDate date];
NSDateComponents *comps = [gregorian components:unitFlags fromDate:date];
これがSiwft2では以下のようになるとリファレンスには書かれている。これだとObjective-Cとさほど代わりはない。
let flags: NSCalendarUnit = .DayCalendarUnit | .MonthCalendarUnit | .YearCalendarUnit
let date = NSDate()
let components = gregorian.components(flags, fromDate: date)
ところがこれを Xcode 7.2.1 で書くと、エラーになってしまってコンパイルできない。
Type of expression is ambiguous without more context
型が分からないというなら直接的に指定するしかないと指定する。
let flags2: NSCalendarUnit = NSCalendarUnit.Day | NSCalendarUnit.Month | NSCalendarUnit.Year
が、するとまた別のエラーになる。
Binary operator '|' cannot be applied to two 'NSCalendarUnit' operands'
じゃあ、一体どう指定するんだよ?と強引に指定するとこんな風になる。
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let flags = NSCalendarUnit(rawValue: NSCalendarUnit.Year.rawValue
+ NSCalendarUnit.Month.rawValue
+ NSCalendarUnit.Day.rawValue
)
guard let comps = calendar?.components(flags, fromDate: date) else {
return
}
let year = comps.year, month = comps.month, day = comps.day
確かにこれだと正常に実行できるんだけど、あまりにも強引すぎてもっときれいな書き方があっていいはずなんだけど。
Swift3ではこんな書き方になる(クラス名等はSwift2のまま)。
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
guard let comps = calendar?.components([.Year,.Month,.Day], fromDate: date) else {
return
}
そしてこれがまたコンパイルが通って正常に実行される。Swift3ではメソッドがSetで定義されているのでこれでもいいのだが、Swift2ではcomponents(flags:NSCalendarUnit, fromDate: NSDate)とNSCalendarUnitで定義されているので[NSCalendarUnit]で渡して渡せる理由がわからない。
そこでこんな書き方をしてみたら、ようやくなぜだかわかった。
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let flags = NSCalendarUnit([.Year,.Month,.Day])
guard let comps = calendar?.components(flags, fromDate: date) else {
return
}
リファレンスとかからはわからないけどNSCalendarUnitのコンストラクタに配列を取るものがあるってことなんでしょう。