はじめに
あるクラスには多くの optional な NSNumber
プロパティがあったとします。
extension MyDailyNumbers {
@NSManaged var open: NSNumber?
@NSManaged var high: NSNumber?
@NSManaged var low: NSNumber?
@NSManaged var closed: NSNumber?
@NSManaged var volume: NSNumber?
}
そして別のクラスが 先のクラスのインスタンスをプロパティとして持ってるとします。さて、これに値を設定するメソッドを考えてみます。そのメソッドの引数の一つ一つは NSNumber
ではなく Int
などでなかった場合に、それらを一つづづ NSNumber
に変換しなければいけません。NSNumber
は optional な値を イニシャライザでとってくれないので、nil
かどうかを区別してあげる必要があります。
スッキリしない解決案
そこで、if let
を使ってこんな風に書いてしまうかもしれません。
class MyObject {
var numbers: DailyNumbers
// [snip]
func setNumbers(open: Int?, high: Int?, low: Int?, closed: Int?, volume: Int?) {
if let open = open {
self.numbers.open = NSNumber(value: open)
}
if let high = high {
self.numbers.high = NSNumber(value: high)
}
if let low = low {
self.numbers.low = NSNumber(value: low)
}
if let closed = closed {
self.numbers.closed = NSNumber(value: closed)
}
if let volume = volume {
self.numbers.volume = NSNumber(value: volume)
}
}
}
上記のコードには大きな問題があります。例えばパラメータに nil
が入っていた場合はそれに相当するプロパティは更新されず、前の値が残ってしまいます。それを仕様だと主張するのも一つの方法ですが、かといって、こんな風に書いたら、きっと目眩さえ感じるかもしれません。
func setNumbers(open: Int?, high: Int?, low: Int?, closed: Int?, volume: Int?) {
if let open = open {
self.numbers.open = NSNumber(value: open)
}
else {
self.numbers.open = nil
}
if let high = high {
self.numbers.high = NSNumber(value: high)
}
else {
self.numbers.high = nil
}
if let low = low {
self.numbers.low = NSNumber(value: low)
}
else {
self.numbers.low = nil
}
if let closed = closed {
self.numbers.closed = NSNumber(value: closed)
}
else {
self.numbers.closed = nil
}
if let volume = volume {
self.numbers.volume = NSNumber(value: volume)
}
else {
self.numbers.volume = nil
}
}
かといってこんなふうにも書きたくありません。
func setNumbers(open: Int?, high: Int?, low: Int?, closed: Int?, volume: Int?) {
self.numbers.open = (open != nil) ? NSNumber(value: open!) : nil
self.numbers.high = (high != nil) ? NSNumber(value: high!) : nil
self.numbers.low = (low != nil) ? NSNumber(value: low!) : nil
self.numbers.closed = (closed != nil) ? NSNumber(value: closed!) : nil
self.numbers.volume = (volume != nil) ? NSNumber(value: volume!) : nil
}
as Number?
そこで、Int
などは NSNumber
に as
オペレータで変換できるので、以下のように as NSNumber?
を使うとスッキリ書くことができます。as? NSNumber
ではありません。
func setNumbers(open: Int?, high: Int?, low: Int?, closed: Int?, volume: Int?) {
self.numbers.open = open as NSNumber?
self.numbers.high = high as NSNumber?
self.numbers.low = low as NSNumber?
self.numbers.closed = closed as NSNumber?
self.numbers.volume = volume as NSNumber?
}
本当は違う方法を記事として書こうとして、書いているうちにこの方法を思い出したのは秘密。決して gist とかを探索しないように。
環境に関する表記
Xcode Version 8.0 (8A218a)
Apple Swift version 3.0 (swiftlang-800.0.46.2 clang-800.0.38)