質問するログイン新規登録
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1663閲覧

guard let self = self else { return } の意味を知りたい

masamasamasa

総合スコア95

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

3クリップ

投稿2019/06/24 01:11

0

3

知りたいこと

guard let self = self else { return } の意味を知りたい

DevelopersIOさんのこのページの「実装」の部分のコードで
guard let self = self else { return }
を見つけたのですが、意味がよく理解できませんでした。

このインスタンスでなければreturnするだと思うのですが、
外部からの侵入を防ぐといったセキュリティの意味合いで書いているのでしょうか?

すみませんが、よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

初心者にはかなりヘビーな内容になります。 覚悟してください。

##短い回答
[weak self] でキャプチャしたselfがクロージャ実行時に存在しているかどうかを確認しています。

##とんでもなく長い回答

guard let else

まず、

swift

1guard let xxx = yyy else { return }

はyyyがOptionalで、yyyに値がなければreturnして値があれば xxx にその値を入れる、という構文です。

例えば以下のように動きます。

swift

1func hoge(_ value: Int?) { 2 gurad let v = value else { return } 3 print(v) 4} 5 6hoge(10) // prints 10 7hoge(nil) // no prints

###変数のキャプチャ
次に、関数による変数のキャプチャというものがあります。

swift

1var val = 0 2 3func fuga() { 4 val += 2 // valをキャプチャ 5} 6 7print(val) // prints 0. 8 9fuga() 10print(val) // prints 2.

関数にキャプチャされた変数valは関数内で値を変更することが可能です。

Swiftでは関数とクロージャは同等のものですので以下でも同じです。

swift

1var val = 0 2 3let fuga = { val += 2 }

###インスタンスのオーナーシップ
最後にクラスのインスタンスのオーナーシップです。
クラスのインスタンスにはデータ領域がありますので、そのインスタンスを使わなくなった時にその領域が解放されなければメモリがひっ迫してしまいます。
しかし、使用中に開放されてしまうと、アプリケーションがクラッシュする事態になります。
このためSwiftではインスタンスにオーナーシップというものを設定しこれに対処しています。
原則として、使用中はオーナーを設定し使用が終わるとそれを外します。オーナーがすべてなくなった段階でインスタンスは解放されます。
これらは自動的に行われており、通常はプログラマは何も考える必要もありません。

ただし、循環参照という状態になるとインスタンスが解放されなくなるため、これを対処する必要があります。

swift

1class A { 2 let b: B 3 4 init(b: B) { 5 self.b = b 6 b.a = self 7 } 8} 9 10class B { 11 var a: A? 12} 13 14let a: A? = A(b: B())

この例は意味のあるコードではありませんが、循環参照の典型的な例です。
class Aのインスタンスはclass Bのインスタンスを、class Bのインスタンスはclass Aのインスタンスを参照しています。
そのため、上の例でa = nilとしてもa, b どちらのオーナーもなくならないため、どちらも解放されません。

この循環参照を回避するためにweakという修飾子が用意されています。
上の例ではclass Bの変数aをweakとします。

swift

1class B { 2 weak var a: A? 3}

このweakという修飾子は「インスタンスは参照するがオーナーとしては登録しない」という指示を与えます。

こうすることでa = nilが実行されると、aのオーナーがすべてなくなりaが解放され、それによってbのオーナーもなくなるためbも解放されるようになります。

###キャプチャによるオーナシップの獲得
まだまだ続きます。

つぎは今までできたことの複合技、キャプチャによるオーナシップの獲得です。

これは名前の通りです。先ほどのclass Aを使います。

swift

1var a: A? = A(b: B()) 2 3let f = { print(a) } // インスタンスaをキャプチャ 4 5a = nil // インスタンスaは解放されない

クロージャがインスタンスaをキャプチャした時、自動的にオーナーが設定されるため、a = nilを実行してもインスタンスaは解放されません。
これにも循環参照の問題が発生します。

swift

1class C { 2 var f: (() -> Void)? 3} 4 5let c: C? = C() 6 7c?.f = { print(c) } 8 9c = nil // c は解放されない

このようにインスタンスcが持つクロージャがcをキャプチャしてしまったため、循環参照が発生し、cが解放されなくなってしまいます。
この時もweak修飾子を使います。ただし、クロージャ自体をweak参照することができないため以下のように行います。

swift

1c?.f = { [weak c] in print(c) }

このweakはcをキャプチャする時にオーナーを設定するなという指示になります。
この指定をすることでc = nilの時にインスタンスcが解放されるようになります。

とこらが、これでも問題が発生する場合があります。class Aを使います。

swift

1var a: A? = A(b: B()) 2 3let f = { [weak a] in print(a) } 4 5a = nil 6 7f() // prints nil

aが解放された後にクロージャfを実行しようとすると、クロージャ内で使用しているaがすでに存在していないためnilになってしまいます。

###キャプチャしたインスタンスの存在確認
では、質問の回答です。
この問題を解決するためには実行前にインスタンスaが存在することを確認する必要があります。
クロージャfを以下のようにします。

swift

1let f = { [weak a] in 2 gurad let a = a else { return } 3 print(a) 4}

まず、gurad let a = a else { return }でインスタンスaの存在を確認し、その後それを使用するようにします。

ご質問のgurad let self = self else { return }も同じことです。
[weak self] でキャプチャしたselfがクロージャ実行時に存在しているかどうかを確認しています。

投稿2019/06/24 07:32

編集2019/06/24 09:07
MasakiHori

総合スコア3391

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masamasamasa

2019/06/24 14:28

ご回答に多大な労力を割いて頂きありがとうございました。満足を通り越して、リスペクトしてしまいました。はやくこのレベルまで行けるように頑張りたいと思います。????????????????????????????????????????????????????????????????????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問