引き続き 強参照循環
を打開するための手段のひとつ、 無所有参照
について眺めていきます。今回はその特徴についての残りの部分と、実際にどのように参照されることになるかを見ていくことになりそうです。よろしくお願いしますね。
————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #233
00:00 開始 00:14 強参照循環って言葉、良くない? 01:27 強参照循環を起こす例の解説 04:05 イニシャライザーで安全に導く 06:32 強参照循環を回避できることについて 07:50 UInt64 を選んだ理由 10:17 処理系を超えるときにも Int のサイズを考慮 13:33 型でデータの整合性を保証する例 14:38 全項目イニシャライザー定義のおはなし 16:18 イニシャライザーが整合性を保証する様子 18:16 UInt64 型について 19:52 符号が要らない場面でも Int を選ぶ 22:24 2の補数表現 24:07 クロージング —————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #233
では、始めていきましょう。今日も引き続き循環参照のお話です。このスライドでは「強参照循環」という言葉を使っていますが、これはあまり聞き馴染みのない言葉かもしれません。ただ、「循環参照」というだけでは弱参照で解決されてしまう問題も多いため、「強参照が循環するから問題になる」という意味で「強参照循環」という言葉の方が適切ではないかと考えています。英語では「Strong Reference Cycle」と言うので、それはわかりやすい表現ですよね。なぜ日本語では「循環参照」になったのか、不思議に思いながらも、この勉強会を通じて「強参照循環」も覚えていただければと思います。
さて、このスライドは前回の復習です。ざっと見た感じ問題なさそうなので、進めていきます。まだ少し説明が残っていますね。ここでは、無所有参照と参照循環のお話をしています。
値のインスタンスをプロパティで保持する関係にある二つのクラスがあり、それらが何も対応しないと強参照循環を形成する問題があります。例えば、クレジットカードとその所有者であるカスタマーのモデルがありますが、クレジットカードが発行されたときにその所有者と関連付けされます。ここで、カスタマーがインスタンスを持ち続けると循環参照が発生するため、強参照循環を断ち切る必要があります。
具体的には、クレジットカードインスタンスがカスタマーより長く存在することはないと判断して、アンオンド(unowned)参照を使うことが有効です。アンオンド参照はカスタマーの存在期間と関係なくメモリ管理ができるため、安全に扱えるということです。
また、クレジットカードインスタンスはカード番号とカスタマーを引数に取る独自のイニシャライザーを持っています。このイニシャライザーで、カード番号と所有者を必ず受け取る設計になっています。つまり、イニシャライザーの作用によって、クレジットカードは必ずその二つの情報を持つという仕様を確立しています。
イニシャライザーの大事なポイントは、インスタンスを確実に初期化する責任を持つことです。これについてはまた別の機会に詳しく触れると思いますので、そこでもっと深く学んでいただければと思います。
さて、クレジットカードが常にカスタマーを持つため、カスタマーのプロパティを無所有参照として定義することで強参照循環を回避します。ここは分かりやすく整理されていない感じがしますが要点としては、クレジットカードとカスタマーの関連付けは必ずあり、無所有参照の使用判断材料はクレジットカードインスタンスがカスタマーインスタンスより長く存在しないため、安全に無所有参照を用いることができるということです。
これで今回の説明は終わりです。次に進みましょう。 前のスライドと意味が違うのかなと思うことがあります。約束されている要素なのかもしれませんね。使用上、生存期間が長いプラス、イニシャライザーによって保証しているからアセットなのですね。保証されていて、かつ、外部からカスタマーを変更できない仕様になっています。
必ず番号と顧客がセットになっていることを型で保証してあげることで、生存期間が長いプラス型による保証によって、万全を期すことができます。エディトカードプラスのナンバープロパティは、16桁のカード番号を32ビットシステムと64ビットシステムの両方で保持しないといけないため、Int
ではなくUInt64
で定義しています。
ここで大事な点として、Swiftでは原則として数値はInt
型で扱うというのがAPIデザインガイドラインでも示されています。この本(『The Swift Programming Language』)はSwift言語の入門書であり、ガイドラインとは異なりますが、公式ドキュメントとしてガイドラインのように使えます。
Swiftでは定数はInt
型として数値を扱う方が互換性や相互運用面でメリットが大きいとされています。特別な場合を除き、明確な型データサイズや符号の有無を示さなければならないときに限りInt
以外の型を選ぶことが提案されています。クレジットカード番号は64ビット数であるべきなのでUInt64
が最適です。
他にも、Int
以外を使わなければならない場面として、プラットフォームを跨いだり、ランタイムライブラリを使用する場合も考えられます。例えば、SwiftでC言語とブリッジする仕組みが備わっていますが、その際もC言語は32ビットシステムを想定しています。
C言語のint
型は32ビットです。したがって、SwiftでC言語の関数を呼び出す場合、例えばexit
関数はint32
を取ります。このようにC言語側が32ビットを期待する場面では、Swift側ではInt32
で渡さなければならないのです。これらの相手先を見据えたときには、Int
以外を使うことが重要です。 面白いケースですね。C言語では普通void
を使いますが、Swiftではその代わりにNever
を使うことがあります。これはデータサイクルの都合によるものですが、確かに興味深い解釈だと思いますね。
それから、型の話に戻りますが、データの整合性を保証するための方法についての説明を続けます。例えば、クレジットカードのインスタンスをプラスして定義する場合の話です。具体的には、次のようになります。
struct CreditCard {
let number: UInt64
let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
}
ここで、number
はUInt64
で定義されており、customer
も別の定義されている型を使います。これにより、初期化の際に必ずクレジットカード番号と顧客情報が必要となり、作成後にこれらの値を変更することはできません。イニシャライザが唯一存在するため、データの一貫性が保証されます。
let card = CreditCard(number: 1234567890123456, customer: someCustomer)
このような形式でインスタンス化することができ、作成後にnumber
やcustomer
を変更するインターフェースは提供されていないため、安全で一貫性のあるデータを扱うことができます。これは、クレジットカード番号や顧客情報が一度設定された後に変更されることがないことを保証するために重要です。
また、UInt64
を使うことで、負の数を排除し、大きな数値を扱うことが可能になります。しかし、Swiftのガイドラインに従うことも重要です。例えば、値段(price
)のように通常はマイナスが考えられない数値を保持する場合には、UInt
を使用するのが良いでしょう。これにより、負の数を誤って入力するリスクを避けられます。
let discount: UInt = 500
このようにして、うっかりとマイナスの値を扱わないようにすることができますね。このような考慮を入れて、適切に型を選択し、コードの安全性と整合性を保つことが大切です。 計算をするときに、例えば「プライス」から「ディスカウント」を引くと、マイナス200円のような結果になることがあります。Swiftではこうった状況に対しても考え方がいくつかあります。基本的にはInt
型で値を扱いますが、マイナス200円になる場合についてはどうするか考えなければなりません。例えば、ガード文でエラーを処理する方法もあります。この点は少し考えなければならないですが、ランタイムエラーが出るよりは事前に対策を講じる方が良いのではないかという意見もあります。
「マイナスが入る可能性がないからUInt
を選ぶ」という発想はあまり推奨されません。桁数の問題で大きい桁数を扱わなければならない場合にはUInt
を選ばざるをえない場合もありますが、それ以外のケースでは慎重に選ぶべきです。
また、マイナスの表現についても触れておきます。現代のコンピューターでは一般的に使われる2の補数表現があります。これは足し算と引き算だけでビット操作ができるため、非常に便利です。他にも1の補数表現がありますが、使用頻度は低いです。2の補数表現について詳しく知りたい場合にはウィキペディアなどで調べると良いでしょう。
2の補数表現は、2進法で表現したときに足し合わせるとちょうど桁が1つ増えてしまうような値のことを指します。このような技術情報は技術者視点でも有用なので、覚えておくと良いでしょう。1の補数表現についても興味がある場合には調べてみると良いですね。
さて、時間になってしまいましたので、今日はこれくらいにしておきたいと思います。お疲れ様でした。ありがとうございました。