Calendar.RecurrenceRule.End を拡張する
Extending Calendar.RecurrenceRule.End
このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。
01 何が問題だったのか
SF-0009 で導入された Calendar.RecurrenceRule では、繰り返しの終了条件を Calendar.RecurrenceRule.End という型で表現します。この型は将来の拡張に備えて enum ではなく struct として定義されており、.afterOccurrences(_:)、.afterDate(_:)、.never の 3 つの static メンバで値を生成できます。
しかし当初の API は値の構築だけを提供しており、構築済みの End から「何回で打ち切る指定なのか」「どの日付で打ち切る指定なのか」を後から取り出す手段がありませんでした。recurrence rule を保存・復元したり UI に反映したりする場面では、終了条件を読み取れないと使い勝手が大きく損なわれます。
加えて、End は print などで文字列化したときに End(_guts: Foundation.Calendar.RecurrenceRule.End.(unknown context at $1a0a00afc)._End.never) のような実装詳細をそのまま出してしまっていました。また、Calendar.RecurrenceRule とそのサブ型は Hashable に適合しておらず、Set や辞書のキーとして扱えませんでした。
02 どのように解決されるのか
Calendar.RecurrenceRule.End に、構築時に渡した値を取り出すための 2 つのプロパティが追加されます。FoundationPreview 6.0.2 以降で利用できます。
extension Calendar.RecurrenceRule.End {
/// `.afterOccurrences(_:)` で構築されたときの回数。それ以外は nil
public var occurrences: Int? { get }
/// `.afterDate(_:)` で構築されたときの日付。それ以外は nil
public var date: Date? { get }
}
occurrences は .afterOccurrences(_:) で初期化された場合のみ値を持ち、date は .afterDate(_:) で初期化された場合のみ値を持ちます。.never の場合は両方とも nil です。当初は元の End の static メンバ名と揃えて count という名前で提案されていましたが、Sequence.count のような既存の意味と紛らわしいため、レビューを経て occurrences に改められました。
let end: Calendar.RecurrenceRule.End = .afterOccurrences(5)
end.occurrences // Optional(5)
end.date // nil
これにより、たとえば既存の recurrence rule を読み出して UI に反映したり、別形式へシリアライズしたりするコードを次のように書けます。
switch (rule.end.occurrences, rule.end.date) {
case let (count?, _):
print("最大 \(count) 回")
case let (_, date?):
print("\(date) まで")
default:
print("無期限")
}
CustomStringConvertible への適合
Calendar.RecurrenceRule.End が CustomStringConvertible に適合し、ケースに応じた読みやすい文字列を返すようになります。これまで print などで露出していた _guts 経由の内部表現は表に出てこなくなります。
print(Calendar.RecurrenceRule.End.never) // "Never"
print(Calendar.RecurrenceRule.End.afterOccurrences(3)) // "After 3 occurrences"
print(Calendar.RecurrenceRule.End.afterDate(someDate)) // "After 2024-02-09 ..."
Hashable への適合
Calendar.RecurrenceRule 本体と、サブ型である Calendar.RecurrenceRule.End / Calendar.RecurrenceRule.Month / Calendar.RecurrenceRule.Weekday が Hashable に適合します。これにより、recurrence rule を Set の要素や辞書のキーとして扱えるようになります。