Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 994 - Macで扱う修飾キーの表示テスト

これからここで使用する「Macの修飾キー」の表示テストをします。Mac環境で読む場合は特に問題なく表示できていますね。Swift関連の記事なんでWindowsで読む人は対象外ということで。

Command Key:⌘
Option Key:⌥
Escape Key: ⎋
Control Key:⌃
Shift Key:⇧
Capslock Key:⇪

上の3つは直接キー入力してます。下の3つはキーコードで表示しています。

皆さん、iOSデベロップメントを諦めてる訳じゃありませんよ。

また戻って来ます。

Swiftで遊ぼう! - 993 - tagを使ってUIViewオブジェクトを扱ったこと無かったです

しばらくプログラミングの勉強から離れていたので、何度も繰り返し勉強したUITableViewControllerを使ったアプリケーションを作っています。

やってみると色々知らないことに出くわしますね。Cellに設置したUIViewクラス継承のオブジェクトをtagを使って制御するという基本的な方法も知らなかったです。

f:id:yataiblue:20171025145721j:plain

上記のように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(_:) が呼ばれます。このメソッドはアプリがバックグラウンドで動き始めているとうシグナルです。次にサスペンド状態に入る前に次のいくつかのステップを踏みます。

  • アプリのユーザーインターフェイスを消去します。表示されている情報を隠して、警告、一時的に表示されているインターフェイスも消し去り、スナップショットを撮るための準備をします。
  • システムと共有しているリソースを解放します。カメラやシステムのデータベースをなど使用しているとシステムは自動的に終了させます。
  • ボンジュール関連のサービスもキャンセルします。
  • 画像、メディアファイル、一時的なオブジェクトもアプリから消去します。NSCacheオブジェクトは自動的に消去されるし、 NSDiscardableContent プロトコールに準拠したオブジェクトも自動的に消去されます。

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を使ったアプリケーションの構造は次のようになっています。

f:id:yataiblue:20171021150605j:plain

アプリケーションを最初に立ち上げた時にシステムが用意している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つの状態のどれか一つのステートに存在します。ステート間の移動(トランジション)には以下のような制限があります。

f:id:yataiblue:20171013183416j:plain

「Active」から「Background」に直接移ることはできないんです。こういう事も知らなかったです。トランジションにも5つのパターンがあります。

  1. Launch:「Not Running」→「Background」or「Inactive」
  2. Activation:「Inactive」→「Active」
  3. Deactivation:「Active」→「Inactive」
  4. Background execution:「Inactive」or「Not Running」→「Background」
  5. 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オブジェクトでシステムが制御している部分です。

このライフサイクルの復習は明日します。