今回は引き続き、個人的にお気に入りな技術ブログ「その Swift コード、こう書き換えてみないか」を眺めていきます。その中の「@ViewLoading
」についての話題に今日から入っていくところです。自分的には知らない機能だったのと、世間的には知られているものか気になって、なかなか面白そうに思いつつ、じっくり観察できたらいいなと思っています。よろしくお願いしますね。
———————————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #275
00:00 開始 00:25 @ViewLoading って使ってる? 02:51 @ViewLoading とは 05:31 @ViewLoading の定義 07:02 @ViewLoading を使う場面 08:05 @ViewLoading は特別扱い 08:58 @ViewLoading な @IBOutlet はオプショナル不要 10:41 アクセスすると自動で View が読み込まれる 12:52 View の読込完了までに初期化されていなければ参照時エラー 13:53 view プロパティーを参照するのと似た動き 15:53 まだ view が読み込まれていないときに何もしない 17:58 所属する ViewController まで辿り着けない 22:00 @ViewLoading も悪くない選択 24:20 サブレイヤーでも特殊な配置方法があったはず 27:00 クロージングと次回の展望 ————————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #275
では、Swiftの続きについて話していきます。今回も引き続き、田中陽馬さんのブログを参考にしています。このブログ、個人的にとても気に入っており、特にSwift関連の情報が満載で大好きです。今回は「AppView Loadingが伝えること」という記事を見ていきます。iOS 16.4以降のUIViewControllerについての話のようです。ちょっと変わったタイトルですが、Swiftの新しい機能について述べられているようです。
私は最近、iOSアプリを作っていないので新しい情報には疎いのですが、AppViewLoadingというのはあまり聞きなれないものでした。この機能は一般的なのでしょうか?それとも特定の場面で使われるのでしょうか?とりあえず、ブログの内容を読んでいくことで理解を深めていくことにしましょう。この機能についてまだよくわからない方も一緒に学んでいきましょう。
ブログでは、この機能について発表された勉強会の内容を元にした記事だそうです。その発表を聞いた方々によるツイートを参考にして、この機能の存在を知ったとのことです。私もそれをきっかけにこの内容を確認してみました。
さて、iOS 16.4以降ではUIViewControllerに特定の設定がなくても、オプショナルとして扱わずに済むそうです。これは以前のバージョンと違い、必ず初期化するインスタンスプロパティをオプショナルにしなくても良いということです。これまでの講義内容にも関係してくる話ですね。JavaやC言語などの他の言語でも似たような問題がありましたが、Swiftでも同様の挑戦が行われているようです。
特に「レイジーバー(lazy var)」を用いたアプローチとの違いについても述べられていました。lazy var
を使うと、オブジェクトが参照された時点で初期化されるため、プログラムの初期化処理がシンプルになります。しかし、ランタイムエラーが発生するリスクがあるため、慎重に扱う必要があります。
実際のコード例では、以下のようなプロパティラッパーを使うと良いとされています。
private var collectionView: UICollectionView!
このように、UICollectionView
をオプショナルにしなくても、ビューがロードされた後に作成することができます。これにより、参照時に初期化が完了していない問題を避けられます。
また、このアプローチでは、ビューのライフサイクルに従って初期化と使用が行われるため、コードの可読性とメンテナンス性が向上します。特に、nil
を代入するリスクを減らせるため、より安全なコーディングが可能となります。
今回はここまでが内容でしたが、このAppViewLoadingについてさらに深掘りしてみたいと思っています。興味深いですね。それでは、Swiftの次のポイントについても引き続き勉強していきましょう。 とりあえず、ビューのローディングはビューコントローラーのビューがどのようになっているかに関するものです。このビューコントローラーにおけるビューローディングのインスタンス化については、よくわからない部分がありました。イニシャライズする際に、このラベルに値を代入しているのですね。ここでラベルが変わるのですね。
@IBOutlet の使い方がよくわからなくなってきました。ソースコードも見れば出てくるのかと思いましたが、UIビューコントローラーであるため、必ずしもそうではないのでしょう。@IBOutlet でエラーが出るのではないかと心配ですし、ビューがロードされる前に @IBOutlet を使おうとするとエラーが発生する可能性があります。
ビューロードの前で使うことができるのかどうかという点についても、不安があります。ビューロードまでの過程でラベルが空っぽという状態なら、その原因も考えられます。また、マクロを使って解決することができるかもしれませんが、現時点ではまだ勉強していないため、正確な判断ができません。
ビューを直接アクセスしない方法でビューのロードをトリガーするという点では、オプショナルを無闇に使うよりは良いかもしれません。この方法で遅延初期化を行うレイジーパターンよりも、明確にビューをロードすることができます。@IBOutlet に比べてリスクは減り、明示的にロードできるため、万全を期すことができます。
PK設計においても、ピューローディングという手法を用いると、プロパティの初期化が明確になります。ViewControllerの仕様として、プロパティを前もってロードすることが重要です。たとえば、ビューのロードをオプショナルにすると、後でエラーが出る可能性もありますが、この問題を適切に処理することで信頼性を高めることができます。
したがって、プロパティロードの前にビューをイニシャライズする方法は、プロパティの仕様を考える上で重要な役割を果たします。UIViewコントローラーのビューローディングを利用して、以下のようなプロパティをオプショナルで返す方法も考えられます:
UIViewController ビューローディング {
var wrappedValue: UIView?
return wrappedValue
}
たとえば、UIViewController で、ラップドバリューがチェックになっているかどうかを確認することができます。ただし、ラップドバリューがある場合でも、エラーが出る可能性があります。そのため、始化の特例を適切に処理する必要があります。
この手法を使えば、エラーが出た場合の対応も含めてより柔軟に対応することができます。ただし、そのためにはコードの各部分がどのように動作しているかを詳細に理解する必要があります。 なるほど、残念ですね。ビューコントローラーまで辿れたのに、もう少しで搭載できそうでした。これが実際に動作する状態なら良かったのに。WrappedValue
がラベルを返しているんですね。しかし、WrappedValue
が隠蔽されていて、外から取り出せないのは困りますね。WrappedValue
が取れれば、特定のオプショナルを使わずに済みそうです。
ビューだとビューコントローラーまで辿れなかったんですよね。ロードビューを走らせることになりかねないので、それを最初にしてしまうと問題です。
いろいろと試した結果、特別な使い方をしないとならないようです。プロパティラッパーを使うとプライベートアクセスができるアンダースコアがつくので、そこで解決できるかと思ったのですが、安全に使える方法がなさそうで残念です。地域によっては使えなかったり、作るのも難しそうですね。面白いとは思いましたけど、この機能を使うのは大前提が必要です。
レイジーパラメータを使うのは危険だと思います。安全なIBOutlet
や、そのIBOutlet
がない独自のコンポーネントを使う場合には、ラベルが使えることを保証するためにこのパッチも悪くないかもしれません。私自身はUIView
を使うとき、なるべくストーリーボードに任せる意識が強いのであまり使いませんが、どうしてもストーリーボードでは対応できないことがあれば、この方法も使ってみたいと思います。
この機能のおかげでビューを通せばアクセスできるようになります。UIView
でやるべきか、親がCALayer
の場合でも変えられるかもしれません。具体的には、以下のようにすれば良いでしょう。
import UIKit
class SomeView: UIView {
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
これでAVPlayerLayer
を使いたい場合、サブレイヤーしなくても、SomeView
自体がAVPlayerLayer
を持つようにできます。
次回の内容ですが、プロトコルの拡張について話し、実装のアイデアを共有する予定です。これも興味深い話題になりそうですね。今日はこれで終わりにします。お疲れ様でした。ありがとうございました。