[ライブラリ] Eurekaの導入と利用〜その2(設定画面の下準備)

はじめに

前回はEurekaをプロジェクトにインストールするところまでの説明をしました。

今回は、Storyboardに設定画面用のView Controllerの追加方法と、設定画面用のクラスファイルを作成する方法を見ていきます。

環境

Xcode:9.2
Swift:4.0.3

Navigation Controllerを追加する

Eurekaは設定画面を簡単に作成することができるライブラリです。ここでは、設定画面を作ることを想定して、サンプルアプリを作成していきます。

そこで、View Controllerの上部にはNavigation Barを表示し、「+」ボタンがタップされた時に設定画面が開かれるようにします。

はじめに、前回作成したプロジェクトを開いてください。EurekaSample1という名前でプロジェクトを作成している場合は、EurekaSample1.xcworkspaceという名前のファイルをダブルクリックして開きます。

続いてMain.storyboardを開きましょう。View Controllerを選択をしたら、メニューから[Editor]-[Embeded in]-[Navigation Controller]を選択します。

Navigation Controllerが追加され、Main.storyboardは以下のようになります。

続いて、View Controllerに配置されたNavigation Barの上にBar Button Itemを1つ配置します。

次に、今配置したBar Button Itemを+アイコンに変更します。配置したBar Button Itemを選択したら、Attributes InspectorのSystem Itemを「Add」に変更します。

これで、「+」アイコンに変更されます。

続いて設定ページ用のView Controllerを追加します。オブジェクトライブラリからMain.storyboardにView Controllerを1つ追加してください。

最後に、先ほどの「+」ボタンをタップした時に設定用ページが開かれるようにします。

「+」ボタンを[control]キーを押しながらドラッグし、追加したView Controllerの上にドロップします。メニューが表示されるので「show」を選択してください。

以上でMain.storyboardの設定は完了です。

完成したMain.storyboardは以下のようになります。

Eurekaを使って設定画面を作成する

ここからは、Eurekaを使用して設定画面を作成していきます。

はじめに、設定画面用のView Controllerクラスを作成します。

メニューから新規ファイルの作成で「Cocoa Touch Class」を作成します。

次にClass名を入力(ここではEurekaViewControllerとしました)してSubclass ofでUIViewControllerを選択して[Next]を選択します。

最後に保存先を選択して、[create]ボタンをクリックします。

今作成したファイルをダブルクリックして開き、「import Eureka」を追加し、継承元を「ViewController」から「FormViewController」に変更してください。

import UIKit
import Eureka   // 追加

class EurekaViewController: FormViewController { // 継承元を変更

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

ここまでできたら[command]+[B]を押して一度ビルドしましょう。

ビルドができたらMain.storyboardを開いて、一番最後のView Controllerに対して今作成したクラスを割り当てます。

以上で下準備は完了です。

次回から設定画面を作成していきます。

[ライブラリ] Eurekaの導入と利用〜その1(ライブラリのインストール)

はじめに

iOSアプリ用の設定画面を作成するには、TableViewを使用するのが一般的です。

しかし、TableViewを利用するには覚えることも多く、1ページ作成するだけでも結構大変です。

そこで、Eureka(ユーリカ)というライブラリを導入すると、簡単にTableViewのページデザインが可能ですので、今回はそのインストールについてみていきます。

環境

Xcode:9.2
Swift:4.0.3

インストール

EurekaのインストールはCocoa Podsを利用します。Cocoa Podsのインストールについては過去記事「CocoaPodsの導入」を参照ください。

はじめにSingle View Appのプロジェクトを作成します。

続いて、Teminalを起動して作成したプロエクト先に移動して以下のコマンドを実行し、podファイルを作成します。

pod init

作成されたpodファイルを開いて、以下のように編集します。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'EurekaSample' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  source 'https://github.com/CocoaPods/Specs.git'
  platform :ios, '9.0'
  use_frameworks!

  # Pods for EurekaSample
  pod 'Eureka'
end

編集が完了したら、Terminalで以下のコマンドを実行してインストールします。

pod install

podファイルの作成からインストールを実行するまでのTerminalのスクショを参考までに載せておきます。

次回以降、実際にEurekaを使用する方法を見ていきます。

[Tips] 使用中のデバイスを判定する

環境

Xcode:9.2
Swift:4.0.3

使用中のデバイスを判定するには?

使用中のデバイスを判定するには、UIDevice.current.userInterfaceIdiomを使用します。

例えば、現在使用中のデバイスがiPadかを調べるには、以下のコードで調べることができます。

if UIDevice.current.userInterfaceIdiom  == .pad {

}

userInterfaceIdiomには以下のような値があります。

説明
phone iPhone
pad iPad
tv Apple TV
carPlay Car Play

[Tips] UIViewControllerをポップオーバーさせるには?

はじめに

今回は任意のUIViewControllerをポップオーバーさせる方法についてみていきます。

ポップオーバーとは、ボタンをタップした時に子画面を表示させることです。

iPadのカレンダーアプリで+ボタンをタップしたときに表示される「新規イベント」のような画面と考えてください。

 環境

Xcode:9.2
Swift:4.0.3

ポップオーバー呼び出し側のデザイン

はじめにSingle View Appのプロジェクトを作成します。

つづいてMain.storyboardを開いて、View Controllerの上部にNavigation Barを配置し、その右側にBar Button Itemを1つ配置してください。

次に、今追加したBar Button Itemを+アイコンに変更します。Bar Button Itemを選択してSystem Itemを「Add」にします。

これで、以下のように+アイコンへと変わります。

ポップオーバーのデザイン

続いてポップオーバーされるビューを作成します。

Main.storyboardにView Controllerを1つ追加してください。

追加したView Controllerが白い背景色だとわかりにくいので別の色を設定しておきます(ここではオレンジにしました)。

次に、ポップオーバーされた時のサイズを変更します。①View Controllerをくりくして選択したら、②Size inspectorを選択します。③Simulated Sizeで「Freeform」を選択したら幅と高さを任意のサイズに変更します。

最後にAttributes inspectorを選択してContent Sizeのところにチェックをつけます。サイズは、先ほど設定した値になっていますので変更せずにそのままとします。

セグエで接続する

呼び出し元と呼び出し先のページができたのでセグエで接続をします。

メインのView Controllerに配置した「+」ボタンをタップした時にポップオーバーされるようにします。

[control]キーを押しながら「+」ボタンをポップオーバーするページへドラッグしてセグエ接続します。このときAction Segueは「Present As Popover」を選択します。

コードの実装

最後にコードを実装します。

メインのViewController.swiftを開いて、

UIPopoverPresentationControllerDelegateを継承させます。

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate  {

次に、以下のコードを挿入してください。

// 前準備
override func prepare (for segue: UIStoryboardSegue, sender: Any?) {
    // セグエのポップオーバー接続先を取得
    let popoverCtrl = segue.destination.popoverPresentationController
    
    // 呼び出し元がUIButtonの場合
    if sender is UIButton {
        // タップされたボタンの領域を取得
        popoverCtrl?.sourceRect = (sender as! UIButton).bounds
    }
    // デリゲートを自分自身に設定
    popoverCtrl?.delegate = self
}

// 表示スタイルの設定
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    // .noneを設定することで、設定したサイズでポップオーバーされる
    return .none
}

上記のコードは2つのメソッドがあります。1つ目のprepareは前準備です。

セグエのポップオーバーの接続先をどこに表示するかの設定を行なっています。

タップされたボタンの下に表示させたいので、prepareの呼び出し元がUIButtonかどうかを判断しています。UIButtonだった場合は、そのUIButtonの位置をsourceRectプロパティに代入し、表示位置を決めています。

もう1つのadaptivePresentationStyleメソッドはポップオーバーが表示されるときのスタイルを設定するためのものです。.noneを返却することで、設定したサイズで表示されるようになります。

実行してみよう

実行をして「+」ボタンをタップすると以下のように「+」ボタンの下にポップオーバー表示されるようになります。

 

 

[Realm] モデルを作成してデータを登録する

はじめに

Realmは様々なプラットフォームで使用可能な軽量データベースです。

Realmのインストールについては、過去の記事「CarthageとRealmのインストール」を参照してください。

本記事では、Realm用のモデル作成とデータの登録方法について備忘録として記載します。

環境

Xcode:9.2
Swift:4.0.3
RealmSwift:3.3.2

プロジェクトの作成

新規でSingle View Appのプロジェクトを作成したら、過去記事を参考にSwiftRealmを導入します。

モデルの作成

ここでは、部署と部署に属する社員を管理するモデルを作成します。

部署モデルでは、「部署名」とマネージャーの「氏名」、部に属する「社員」を管理できるようにします。

新規で「Department.swift」というSwift Fileを作成し、Departmentクラスを以下のように作成します。

import Foundation
import RealmSwift

class Department: Object {
    // 部署名
    @objc dynamic var name : String = ""
    // マネージャーの氏名
    @objc dynamic var manager : String = ""
    // 部に属する社員
    let employees = List<Employee>()
    
    // プライマリーキー
    override static func primaryKey() -> String? {
        return "name"
    }
    
    // インデックス
    override static func indexedProperties() -> [String] {
        return ["name"]
    }
}

Realm用のモデルを作成するには、「import RealmSwift」が必要です。また、クラスはObjectを継承する必要があります。

モデルに登録するそれぞれの項目はプロパティとして定義します。このとき「@objc dynamic var」で宣言します。

プロパティで使用できるデータ型にはBool、Int、Int8、Int16、Int32、Int64、Double、Float、String、Date、とDataがあります。

部署名やマネージャーの氏名は文字列を登録しますのでString型にしています。

また、部に属する社員は複数登録できるようにList<epmplyee>としています。

次に、社員を管理するEmplyeeクラスを作成します。このクラスは先ほど作成したDepartment.swiftの中に作成しても構いません。

class Employee : Object {
    // 社員の氏名
    @objc dynamic var name: String = ""
    // 社員の年齢
    @objc dynamic var age: String = ""
}

以上でモデルの作成は完了です。

データを登録してみる

それではデータを登録してみましょう。

はじめに部署のみを登録する方法をみてみます。

let realm = try! Realm()  // Realmの初期化

// Engineer型オブジェクトの作成
let dept = Department()
// Realmへのオブジェクトの書き込み
try! realm.write {
    dept.name = "システム部"
    dept.manager = "Bill"
    realm.add(dept)
}

はじめにRealmの初期化を行います。

次に、部署を管理するEngineerのオブジェクト(インスタンス)を作成します(4行目)。

あとは、realm.writeメソッドを使用してデータを登録します(6行目以降)。

Realm Browserで確認すると以下のようにデータが登録できていることが確認できます。参考「[Tips] Realmファイルの保存先を知るには?

この時点ではEmployeesは「0」になっているので登録されていないことがわかります。

子データを登録する

今度は、部署に属する社員を登録してみましょう。

社員を登録するには、まず登録先の部署を検索して取得する必要があります。

検索するにはRealmインスタンスのobjectsが持つfilterメソッドを使用します。以下にコード例を示します。ここでは「nameが’システム部’と等しい」を条件にして抽出しています。

let realm = try! Realm()
let dept = realm.objects(Department.self).filter("name == 'システム部'").first

つづいて、部に追加する社員を作成します。

let emp = Employee()
emp.name = "Oscar"
emp.age = "23"

あとは、writeメソッドを使用して登録をするだけです。部を検索して社員を登録するまでのコードを以下に示します。

let realm = try! Realm()
let dept = realm.objects(Department.self).filter("name == 'システム部'").first
let emp = Employee()
emp.name = "Oscar"
emp.age = "23"
try! realm.write {
    dept?.employees.append(emp)
}

登録が成功すると以下のように社員が登録できていることを確認できます。

子データを削除する

続いて子データを削除してみましょう。

先ほどのfilterメソッドを使用して、システム部を検索し、さらにシステム部に属する「Oscar」を削除する場合は以下のようにします。

// 子データの削除
let realm = try! Realm()
let dept = realm.objects(Department.self).filter("name == 'システム部'").first
let emp = dept?.employees.filter("name == 'Oscar'").first

try! realm.write {
    realm.delete(emp!)
}

削除はrealm.writeメソッドの中で「realm.delete(削除したいオブジェクト)」とします。

親データを削除する

親データも子データ同様にfilterメソッドで特定して削除をします。

// 親データの削除
let realm = try! Realm()
let dept = realm.objects(Department.self).filter("name == 'システム部'").first

try! realm.write {
    realm.delete(dept!)
}

Realmファイルを削除するには

Realmによるデータは、Realmファイルに格納されます。何らかの事情でリセットしたい場合は以下のコードを書くことでまっさらにすることができます。

let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
let realmURLs = [
    realmURL,
    realmURL.appendingPathExtension("lock"),
    realmURL.appendingPathExtension("note"),
    realmURL.appendingPathExtension("management")
]
for URL in realmURLs {
    do {
        try FileManager.default.removeItem(at: URL)
    } catch {
        // handle error
    }
}

[Tips] Realmファイルの保存先を知るには?

RealmのデータベースファイルはRealm Browserというツールで確認できます。しかし、アプリで作成したデータベースファイルがどこにあるかは非常にわかりにくくなっています。

データベースファイルがどこにあるのかを知るには、Realmの初期化の後にprint文で場所を調べます。

let realm = try! Realm()  // Realmの初期化
print(Realm.Configuration.defaultConfiguration.fileURL!)

[Tool] Xcodeプラグイン Alcatraz をインストールする

Alcatrazとは

Xcodeに「Alcatraz」をインストールすると、Xcodeから様々なプラグインを導入できるようになります。

環境

Xcode:9.2

Alcatrazのインストール

はじめに、Xcodeを終了しておきましょう。

続いてターミナルを開いて以下のコマンドを実行します。

curl -fsSL https://raw.github.com/supermarin/Alcatraz/master/Scripts/install.sh | sh

実際に実行したときのスクリーンショットを以下に載せておきます。

AlcatrazはXcode8以降に対応していないため、以下のコマンドで使用できるようにします。

はじめに、gemを使ってupdate_xcode_pluginsをインストールします。

sudo gem install -n /usr/local/bin update_xcode_plugins

次にインストールしたupdate_xcode_pluginsを実行します。

update_xcode_plugins

このままでは動作しないプラグインがあるため、以下コマンドを実行します。

Xcodeを起動して確認する

最後にXcodeを起動してAlcatrazがインストールされているかを確認します。

Alcatrazインストール直後のみ以下のようにダイアログが表示されるので[Load Bundle]をクリックします。

メニューのWindowsに「Package Manager」があれば成功です。

 

 

 

[UI部品] Container View

Container Viewとは

Container Viewを使用すると、View Controllerの中に別のViewを組み込むことができます。

複雑な画面を作成する場合は、View Controllerを複数のContainer Viewを配置すると管理が容易な場合がありますので必要に応じて使用すると良いかと思います。

環境

Xcode:9.2
Swift:4.0.3

Container Viewを使ってみよう

はじめにSingle View Applicationのプロジェクトを作成して、Container Viewを貼り付けます。配置したら、サイズを任意の大きさに変更してください。

Container Viewを貼り付けると、貼り付けたContainer Viewと同じ大きさのView Controllerが追加されます。貼り付けたContainer Viewのサイズを変更すると、追従して大きさが変わります。

あとは、追加されたView Controllerを適当にデザインします。ここでは背景色をオレンジにして、Labelを1つ貼り付けてみましょう。

View ControllerからContainer Viewを操作する

はじめに、先ほど配置したContainer View専用のViewControllerクラスを作成しましょう。

メニューの[File]-[New]-[File]を選択して、一覧から「Cocoa Touch Class」を選択します。

次に任意のクラス名を入力して(この例ではContainerViewController)、継承元のクラスをUIViewControllerにします。

最後に保存先を選択して、ファイルを作成します。

続いて、作成したクラスをContainer Viewに割り当てます。Main.storyboardを開いてContainer Viewを選択したら、Class欄に先ほど作成したクラス名を入力します。

続いて、ViewCotrollerからContainer Viewに貼り付けたLabelに文字を表示できるようにしてみます。

はじめにLabelのアウトレット接続を作成します。ContainerViewControllerクラスにlblContainerMsgという名前でアウトレット接続を作成します。

続いて、showMsgという名前のメソッドを実装します。このメソッドは親のView Controllerから呼び出して、Container Viewに貼り付けたLabelにメッセージを表示するためのものです。

class ContainerViewController: UIViewController {

    @IBOutlet weak var lblContainerMsg: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func showMsg(msg : String) {
        lblContainerMsg.text = msg
    }

}

次に、親のページにText FieldとButtonを貼り付けます。Text FiledにはtextMsgという名前でアウトレット接続を作成し、ButtonにはshowButton_Tappedという名前のアクション接続を作成します。

最後にshowButton_Tappedメソッドの中身を実装します。Container ViewはchildViewControllersで取得することができます。現時点ではContainer Viewを1つしか配置していないので、childViewControllers[0]で特定することができます。Container Viewを取得できたら(ここでは変数childVCに取得しています)、先ほど実装したshowMsgメソッドを呼び出すことができます。

以下のように実装すると、textFieldに入力した文字を、Container ViewのLabelに表示することができます。

@IBAction func showButton_Taped(_ sender: Any) {
    // Container Viewを取得する
    let childVC = childViewControllers[0] as! ContainerViewController
    // Container ViewのshowMsgメソッドを呼び出す
    childVC.showMsg(msg: textMsg.text!)
}

Container Viewから親のView Controllerを操作する

今度はContainer Viewから親のView Controllerを操作してみましょう。

はじめに親のView ControllerにLabelを1つ貼り付けてアウトレット接続を作成します。ここではlabelMsgという名前で作成します。また、Container Viewから親のView Controlerを操作するためのshowMsgメソッドを実装します。このshowMsgが呼ばれるとContainer Viewからのメッセージを表示します。

showMsgのコードを以下に示します。

func showMsg(msg : String) {
    labelMsg.text = msg
}

次に、Container ViewにButtonを1つ貼り付けて、showButton_Tappedというアクション接続を作成します。

showMsg_Tappedのコードを以下に示します。

@IBAction func showMsg_Tapped(_ sender: Any) {
    let parentVC = self.parent as! ViewController
    parentVC.showMsg(msg: "テスト")
}

実行してView Controllerの[表示]ボタンをタップすると以下のようにView Controllerに「テスト」と表示されます。