Swiftで遊ぼう! - 993 - tagを使ってUIViewオブジェクトを扱ったこと無かったです
しばらくプログラミングの勉強から離れていたので、何度も繰り返し勉強したUITableViewControllerを使ったアプリケーションを作っています。
やってみると色々知らないことに出くわしますね。Cellに設置したUIViewクラス継承のオブジェクトをtagを使って制御するという基本的な方法も知らなかったです。
上記のようにCell上にUILabelを設置します。これをUITableViewControllerファイルで次のように操作します。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) let label = cell.viewWithTag(1000) as! UILabel label.text = "Run" return cell }
viewWithTag()メソッドを使うのは初めてでした。こういうやり方もあったんですね。
Swiftで遊ぼう! - 992 - Preparing Your App to Run in the Background
Preparing Your App to Run in the Background | Apple Developer Documentation
5つのアプリケーションの状態から5つのトランザクションを経て状態が変化します。Activeなアプリケーションからバックグラウンドに移るときに直接移行できないって以前話しました。
まずdeactivationに入らないといけないので、このときapplicationWillResignActive(_:) が呼ばれて、次の4つのタスクが実行されます。
- ユーザーデータをディスクに保存してオープンしているファイルはすべて閉じられます。
- ユーザーのデータを保持する重要なタスクだけこなします。ディスパッチ・キュー、オペレーション・キューも中断して新しい実行タスクは開始されません。
- アクティブなタイマーは止められます。
- ゲームプレーも中断します。
これはディアクティベーションのステップで、次はバックグラウンドに移るんですが、applicationDidEnterBackground(_:) が呼ばれます。このメソッドはアプリがバックグラウンドで動き始めているとうシグナルです。次にサスペンド状態に入る前に次のいくつかのステップを踏みます。
Swiftで遊ぼう! - 991 - Preparing Your App to Run in the Foreground
Preparing Your App to Run in the Foreground | Apple Developer Documentation
UIKitを使ったアプリケーションを組み立てる時に知っておかなければならないメソッドの勉強をしています。前回はapplication(_:willFinishLaunchingWithOptions:) とapplication(_:didFinishLaunchingWithOptions:) の使い分けを勉強しました。この2つのメソッドはあくまでもアプリのユーザーインターフェイスが描画される前に実行されます。
次はアプリがアクティブになった時に呼ばれるメソッドの説明です。
アプリケーションがスクリーン上でアクティブなったときにUIKitはapplicationDidBecomeActive(_:)を呼びます。バックグラウンドからフォーグラウンドに移るときもこのメソッドは呼ばれますが、その前にapplicationWillEnterForeground(_:) が呼ばれます。
applicationDidBecomeActive(_:)メソッドが戻されたときに全てのwindowsは表示されるし、viewsがまさに表示される時にview controllerに通知(Notification)が送られます。
viewsの内容をアップデイトするためにviewWillAppear(_:) を使用します。インターフェイスが画面に表示された後ならviewDidAppear(_:)を使うといいです。
Swiftで遊ぼう! - 990 - Responding to the Launch of Your App
Appleのドキュメントを読んで理解できるのはちょっと嬉しいですね。
Launchトランザクションで何が起こるのか理解しましょう。
Responding to the Launch of Your App | Apple Developer Documentation
UIKitを使ったアプリケーションの構造は次のようになっています。
アプリケーションを最初に立ち上げた時にシステムが用意しているUIApplicationが立ちあがります。これはシステムが制御するものでユーザーは変更することができません。UIApplicationはユーザーに制御させるためにUIApplication Delegateというプロトコールを用意しているのでそれを使って制御します。ということでUIApplication Delegateはカスタム・オブジェクトになるんです。
アプリケーションが最初に立ちあがる時にこの2つのプロトコールを使えます。
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { // Override point for customization after app launch, // but before state restoration. return true } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for app customization // Perform final customization of your user interface. }
application(_:willFinishLaunchingWithOptions:) はアプリがストーリーボードからユーザーインターフェイスのオブジェクトを読み込んだ直後1度だけ呼ばれます。application(_:didFinishLaunchingWithOptions:) はアプリがコンテンツの利用するタイミングやインターフェイスをアップデイトしたりタスク開始のタイミングで呼ばれます。
これらのメソッドが実行されてUIKitに戻ってくるまでユーザーインターフェイスは表示されません。このメソッドは非同期、もしくはバックグラウンド・ディスパッチで実行させるのが原則です。
まずホームボタンでアプリのアイコンをタッチするとシステムはアプリの起動を始めるんですが。そのとき、dictionary型のオブジェクトを上記のメソッドに渡すんです。
dicutionary型のオブジェクトは単にkeysを保持しているだけで、これにより適切な起動を行えるようにするんです。例えば、アプリのバックグラウンドでロケーションをアップデイトさせるためにdicitionary型オブジェクトにlocationキーが含まれていると次のように記述することでlocationに応えることができます。
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { let locationManager = CLLocationManager() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // If launched because of new location data, // start the visits service right away. if let keys = launchOptions?.keys { if keys.contains(.location) { locationManager.delegate = self locationManager.startMonitoringVisits() } } return true } // other methods… }
なんとなく理解はできます。
Swiftで遊ぼう! - 989 - Managing Your App's Life Cycle
今までチュートリアル以外のAppleから公開されている正式なドキュメントを読み進めたことが無かったのでいい勉強になっています。
Managing Your App's Life Cycle | Apple Developer Documentation
App delegateの働きもなんとなく分かっていたつもりでした。しかし、このドキュメントを読んで全体像が把握できたような気がします。アプリケーションは常に5つの状態のどれか一つのステートに存在します。ステート間の移動(トランジション)には以下のような制限があります。
「Active」から「Background」に直接移ることはできないんです。こういう事も知らなかったです。トランジションにも5つのパターンがあります。
- Launch:「Not Running」→「Background」or「Inactive」
- Activation:「Inactive」→「Active」
- Deactivation:「Active」→「Inactive」
- Background execution:「Inactive」or「Not Running」→「Background」
- Termination:5つのいかなる状態からでも「Not Running」に移行
ここの説明を読んでいると「Suspend」への移行をコントロールできないみたいです。システムが自動的に制御しているようでSuspendからアプリへのNotify無しでNot Runningに移行もします。
今日はここまで。
Swiftで遊ぼう! - 988 - About App Development with UIKit
さあドキュメントを読むことから再開しています。UIKitを使ったアプリケーション開発の基本はMVCモデル!
About App Development with UIKit | Apple Developer Documentation
MVCモデルの基本しか理解していなかったので、ここでもう少し深い内容が学べました。UIKitではModelオブジェクトとしてUIDocumentが用意されています。知らなかったんですが、名前が示すようにModelオブジェクトのデータを扱うのでだと思います。でもロジックパートは独自に実装する必要がありますね。このUIDocumentを使うのであればControllerオブジェクトとしてApplication Delegateを介してViewControllerで制御するのが一般的です。この扱いはModelオブジェクトにCoreDataを扱うときと同じですね。
Viewオブジェクトは最上位にUIWindowがありますが、Application Delegateから意識しないで扱うようになっています。一つ重要なオブジェクトがあります。アプリケーションのイベントループをコントロールするUIApplicationオブジェクトです。これはアプリのライフサイクルを制御するのですがControllerオブジェクトでシステムが制御している部分です。
このライフサイクルの復習は明日します。