今回は、前回に紹介してサンプルコードを元に 循環参照
の具体的な様子と、そこに見られる問題点のあたりを詳しく眺めていきます。毎度のように出てくる循環参照ですけれど、その基本的な動きの様子を再確認するちょうど良い機会な気がしますので、どうぞよろしくお願いしますね。
——————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #216
00:00 開始 00:09 前回のおさらいと今回の展望 01:49 参照の様子を図式してみる 03:52 引用とか著作権とかの話 08:17 循環参照を形成していく 09:03 オプショナル型で扱う値のプロパティーに代入するとき 10:00 循環参照の図式 11:25 強参照循環、今後の展望 11:56 オプショナル型への代入の話 12:30 ! だけでなく ? でも代入可能 15:13 代入先が nil だったときの挙動 15:41 戻り値が Void のオプショナル 17:13 代入演算子 20:35 代入演算子の自作は知識不足で失敗 21:56 手がかりを探してみるも、見つけられず 23:25 クロージングと次回の展望 ———————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #216
はい、では始めていきますね。今日は引き続き順番参照についてお話します。具体的な例題を見ながら、準備が整った段階ですね。
まず、「Person」と「Apartment」という2つのクラスを作成します。それぞれのクラスについてもう一度おさらいしましょう。Person
は人を表し、Apartment
はアパートを表します。アパートには部屋番号があり、その部屋に人が入るかどうかを示します。しかし、部屋に人が入っていない可能性もあるので、その設計はオプショナルで行います。同様に、Person
の方もどのアパートに、どの部屋に入っているかを持ちますが、必ずしも契約しているわけではないため、これもオプショナルで設計されています。
ここでもう一度確認してみましょう。パーソンオブジェクトとアパートオブジェクトを作り、それぞれがどの部屋にいるか、どの部屋に人が入っているかを確認します。しかし、人が入っていない状態も考慮するため、オプショナルで設計します。
次に、この2つのクラスのインスタンスを生成してみました。部屋のインスタンスを生成しましたが、この時点ではどこにも部屋が入っておらず、この部屋にも誰も入っていないという状況です。この状況を図式してみましょうというのが次のスライドになります。2つの変数とそれぞれのインスタンスがどのようになっているか注目して見てみてください。
次の段階としては、パーソンの名前が「ジョン」であるインスタンスと、ユニットが「4A」であるアパートのインスタンスを生成しました。それぞれ共参照(共有参照)で保持しています。このとき、中間参照がまだ起こっていないことが確認できます。
変数に独立したインスタンスを入れる限り、パーソンとアパートメントの相関関係はなく、この段階ではシンプルな参照で共参照する必要もありません。
ここまでの説明では特に問題はありませんが、Swiftプログラミングランゲージに沿って説明してきている中で、今回初めて図が出てきました。引用元についても記載が必要ですので、後で引用元を追加しておきます。著作権にも注意を払う必要がありますね。
最近では、SNSのアイコンに著作権が設定されている絵を使用している場合も多く、こういった細かいところにも気を配ることが重要です。例えば、国際カンファレンスに参加する際には特に注意が必要です。著作権を無視して漫画のカットを使用することも議論されており、フェアユースという概念が米国では認められていますが、日本ではまだ問題となることがあります。
いずれにせよ、発表の内容をサポートするために適切に引用することが重要です。これにより聞き手の記憶に留まりやすい発表ができますが、逆に嫌悪感を与えることもあるため、使い方は慎重に考える必要があります。
以上が本日の内容となります。次回も引き続きSwiftの順番参照について学んでいきましょう。 著作権については難しい面がありますが、最も大切なのは著作権を尊重することです。それを時々思い返してみると良いでしょう。それでは、話を進めます。
Swift言語の参照についての話です。まず、ジョンとユニット4Aというインスタンスがあります。ここで契約が成立したということは、ジョンさんがユニット4Aの部屋に入り、ユニット4Aにはジョンさんが入っているという両者に記録された状況です。
この注意書きが面白いのは、ジョンとユニット4Aがともにオプショナル型で宣言されている点です。そのため、代入するときに強制アンラップ(!
)を使って代入します。この準備は循環参照チェックのためにオプショナルになっていますが、循環参照を作る上での重要な点ではないので、それほどこだわらなくて良いです。
リンクができた状況を確認すると、ジョンさんがアパートメントを参照し、アパートメントが再びジョンさんを参照しています。これが循環参照です。循環参照が形成されると問題が発生する可能性があるという話が今回のメインテーマです。
前のスライドに面白いことが書いてあったので、それを補足します。オプショナル型についての話でしたね。昔の言語仕様だとこんな感じで面白いことがあって、このコードを用いて説明します。Person
とApartment
のインスタンスを作り、両方オプショナルで設計されています。このコードは問題なく動いています。代入するときに強制アンラップ(!
)を使うことでエラーなく動作します。
次に、もしUnit4A
のテナントを表示してみると、ジョンさんが中に入っている状況が確認できます。ここでアテナ(Optional)の代入が適切に行われていることも確認できます。以下のように表示されます:
print(john.apartment!.unit) // "4A"
print(unit4A.tenant!.name) // "ジョン"
しかし、もしオプショナルのアンラップ(ビックリマーク!
)が失敗すると、ランタイムエラーが発生します。例えば、ジョンさんをアンラップしようとすると次のようにエラーが発生します:
print(john.apartment!.unit) // アンラップエラー
この場合、当然ランタイムエラーが起こります。この注意点を踏まえて、オプショナル型の取り扱いに注意する必要があります。 ジョンさんがnil
なのでアパートメントにアクセスしようとすると落ちます。ここをオプショナルにするとオプショナルチェーン的な動きをします。つまり、ジョンさんがnil
でなければ代入が行われるということです。そして、そのままの状態で正常にnil
が返っていますね。
この勉強会では以前、Voidのオプショナルの話をしました。思い出す人は思い出してもらえればと思います。代入演算子が実行できなかったのでnil
が返りましたね。でも、ユニット4aにはちゃんとインスタンスが入っています。そのペナントにはジョンさんがnil
であっても、ペナント型がオプショナルであるため、代入可能です。ここは正常に動作し、Voidが入るということです。オプショナルチェーン的に代入演算ができて、ちゃんと動くユニット4aがあります。ただ、ペナント型なので、ネームもカラでnil
であることがわかります。
補足ですが、ジョンさんは実際にnil
なので、nil
として継続して動くことができます。こんな感じで、Objective-C的な動きができるわけですから、この演算は有用です。
しかし、これがすぐに使えるわけではなく、たとえば独自の演算子を定義することに挑戦してみますか。たとえば、infix
オペレーターを使ってみましょう。まず、パラメータとして両方とも使用したいので、Person
のオプショナルとApartment
のオプショナルを使います。このとき、演算子があると、ジョンさんの演算のユニットとアパートメントがジョンさんのアパートメントとなります。詳しく分からないので、いろいろやってみましょう。なのでアパートメントをオプショナルにしていきます。
そして、右辺に対してこれを実行してみましょう。全然違いますね。これはinfix
オペレーターなので、対応する処理を行う必要があります。ジョンさんとパラメータになる.has
を使ってPerson
とパーソンにできます。この時にフェイタルエラーが出るのは、nil
にしたからです。Person
を入れておき、これでどうなるかを見てみましょう。動いているかわかりませんが、オプショナルだった時にはアパートメントとなります。少し複雑なのでやめて、他のインアウトの演算子定義を見てみます。
たとえば、+=
の定義を見ると、これはインアウトです。struct
としてValue
があります。var x: Int
として宣言して、Value
のインスタンスを作ったとして、optional
だった場合、Value.x
に10を入れたいとします。この時、普通に動くと思いますが、実際動いていますね。Value.x
は10となり正常です。この時、インフィクスオペレーターを公開し、新しい処理を定義します。
次回またお話ししましょうか。設定すると、オプショナルが相手である時にもちゃんと解釈してくれるものがあります。少なくとも以前のバージョンではそのようになっていましたが、仕様が変わったので今はどうなっているか確認しましょう。ただし、当時の特別な代入演算子の定義があったと思うので、調査して次回報告します。
今日は時間になったので、これで勉強会を終わりにします。お疲れ様でした。ありがとうございました。