値があることを知っていることを意味するのに、なぜ「暗黙的にアンラップされたオプション」を作成するのですか? 質問する

値があることを知っていることを意味するのに、なぜ「暗黙的にアンラップされたオプション」を作成するのですか? 質問する

通常の変数や定数を作成するのではなく、「暗黙的にアンラップされた Optional」を作成するのはなぜですか? 正常にアンラップできることがわかっているのに、そもそもなぜ Optional を作成するのでしょうか? たとえば、これはなぜでしょうか:

let someString: String! = "this is the string"

以下よりも便利です:

let someString: String = "this is the string"

「オプションは、定数または変数が「値なし」を持つことが許されることを示す」が、「プログラムの構造から、オプションが最初に設定された後は必ず値を持つことが明らかな場合がある」場合、そもそもオプションにする意味は何でしょうか? オプションが必ず値を持つことが分かっている場合、それはオプションではないということになりませんか?

ベストアンサー1

暗黙的にアンラップされたオプショナルの使用例を説明する前に、Swiftにおけるオプショナルと暗黙的にアンラップされたオプショナルが何であるかを理解しておく必要があります。もしまだ理解していない場合は、まず以下を読むことをお勧めします。オプションに関する私の記事

暗黙的にアンラップされたオプションを使用する場合

暗黙的にアンラップされた Optional を作成する主な理由は 2 つあります。いずれも、アクセスされることのない変数を定義することに関係しています。nilそうしないと、Swift コンパイラによって常に Optional を明示的にアンラップするように強制されるからです。

1. 初期化時に定義できない定数

すべてのメンバー定数は、初期化が完了するまでに値を持っている必要があります。初期化中に定数を正しい値で初期化できない場合もありますが、アクセスされる前に値が設定されていることが保証されます。

Optional 変数を使用すると、この問題を回避できます。Optional は自動的に初期化されnil、最終的に含まれる値は不変のままです。ただし、nil でないことが確実な変数を常にアンラップするのは面倒です。暗黙的にアンラップされた Optional は、Optional と同じ利点に加えて、どこでも明示的にアンラップする必要がないという利点もあります。

この良い例は、ビューが読み込まれるまで UIView サブクラスでメンバー変数を初期化できない場合です。

class MyView: UIView {
    @IBOutlet var button: UIButton!
    var buttonOriginalWidth: CGFloat!

    override func awakeFromNib() {
        self.buttonOriginalWidth = self.button.frame.size.width
    }
}

ここでは、ビューが読み込まれるまでボタンの元の幅を計算することはできませんが、awakeFromNibビューの他のメソッド (初期化以外) の前に呼び出されることはわかっています。クラス全体で値を無意味に明示的にアンラップする代わりに、暗黙的にアンラップされた Optional として宣言できます。

2. アプリが変数の異常から回復できない場合nil

これは非常にまれなケースですが、変数にアクセスしたときにアプリが実行を継続できない場合はnil、 をテストするのは時間の無駄ですnil。通常、アプリの実行を継続するために絶対に真でなければならない条件がある場合は、 を使用しますassert。暗黙的にアンラップされた Optional には、nil のアサートが組み込まれています。その場合でも、optional をアンラップし、nil の場合はより説明的なアサートを使用する方がよいことがよくあります。

暗黙的にアンラップされたオプションを使用しない場合

1. 遅延計算されたメンバー変数

時々、nil になるはずのないメンバー変数があるのに、初期化中に正しい値に設定できないことがあります。 1 つの解決策は、暗黙的にアンラップされた Optional を使用することですが、より良い方法は遅延変数を使用することです。

class FileSystemItem {
}

class Directory : FileSystemItem {
    lazy var contents : [FileSystemItem] = {
        var loadedContents = [FileSystemItem]()
        // load contents and append to loadedContents
        return loadedContents
    }()
}

これで、メンバー変数はcontents最初にアクセスされるまで初期化されません。これにより、クラスは初期値を計算する前に正しい状態になる機会が得られます。

注:これは上記の #1 と矛盾しているように見えるかもしれません。ただし、重要な違いがあります。buttonOriginalWidthプロパティにアクセスする前に誰かがボタンの幅を変更できないようにするには、viewDidLoad 中に上記を設定する必要があります。

2. その他

ほとんどの場合、暗黙的にアンラップされた Optional は使用しないでください。誤って使用すると、 while にアクセスしたときにアプリ全体がクラッシュしますnil。変数が nil になるかどうかわからない場合は、常に通常の Optional を使用するようにしてください。nil にならない変数をアンラップしても、nilそれほど問題にはなりません。

おすすめ記事