日々、徒然プログラミング。

都内のIT系専門学校に通う、一人暮らし女子学生chocoffeeの、 日々の気づきと学び、たまにほっこりを綴るブログ。

エンジニアのみなさま、エンジニアの卵のみなさま、IT業界のみなさまが
わたしの「チームってなんだ?」というぼやきに反応してくださることを祈って。

2016年04月



こんばんは!
猫になりたいちょこひです。

今みたいに充実した日々ももちろん楽しいけど、
たまに猫になって日向でごろにゃーしたくなる。

 
今回作成するテストアプリ 

前回記事の通り、今回はDelegateを使ったサンプルアプリを作成します。
全体的な動きは
・Viewは2つのみ
・1つ目のViewにtextFieldとButtonを配置、Buttonから2つ目のViewにModalとして遷移
・2つ目のViewに LabelとButtonを配置、1つ目のTextFieldに入力された文字列をLabelに表示、Buttonで2つ目のモーダルビューを閉じる

という簡単なものです。

使うDelegateは
2つ目のモーダルビューを閉じる」部分と、
textField入力時、キーボードのreturnボタンでキーボード自体を閉じる
の2点です。

キーボード自体を閉じる動きはDelegateの鉄板。

Segueを通して文字列を渡す動きは、前回のTableViewControllerの復習を兼ねています。 

以下ss。

38



43

returnキーでキーボードの終了。

46

sendボタンで画面遷移。


50

backボタンでモーダルビューの終了。


では、行きましょう。

 
StoryBoard


・ViewController
09
サイズは適当です。上部にtexiField、下部にButtonを置いて、sendに変更。



・ModalViewController

38

こちらも適当。
わかりやすくするために背景色を変えています。


・sendボタンからModalViewへSegueをつなぐ

presentModaly


前回は「Show」を選択していましたが、今回は「Present Modally」を選択。
これで、2つ目のViewはモーダルビューになります。


・SegueにIdentifierを設定

24


今回はmodalSegueというIdentifierをつけました。


・新規ファイル「ModalViewController.swift」を作成

16

今回もcocoaTouchで作成しました。


・ModalViewControllerとModalViewController.swiftをつなげる

44

storyBoardにて参照先クラスを設定します。




・各クラスにそれぞれのパーツをつなげる

2画面モード(名称なんでしたっけ)にして、

ViewControllerのtextField(Outlet)
ModalViewControllerのLabel(Outlet)とButton(Action) を
つなげます。
 
textField
32
「textField」という名称にしました。


Label
06
「label」という名称にしました。


Button
16
「backToFirst」という名称にしました。


これで、ひとまずは準備OK!



 
ModalViewController.swift


では、ソースコードをいじっていきます。

2つありDelegateのうち、ModalViewを閉じる方は

処理を依頼する側=ModalViewController.swift
処理を依頼される側=ViewController.swift 

です。 まずはこちらを先に実装します。


・protocolの宣言

前回記事の通り、protocolとは「依頼する文書」のことです。これを仲介して実際に依頼します。

//  ModalViewController.swift

protocol dismissModal {

    func dismiss()

}


今回は、protocolの名称を「dismissModal」とし、
実際に依頼する処理名を「dismiss」としました。

この時、dismiss()メソッドには何も書きません。引数と、その型、あるなら戻り値のみ書きます。
Javaでいうinterfaceと同じです。

最近、「protocol extention」とかいうものが出たらしく
AndroidJavaでいう抽象クラスのようなものがあるらしいです。聞かなかったことにします。

このprotocolを2つのクラスでなんやかんやして行きます。

具体的には

ModalViewController.swift「自分自身の終了はできないから、ViewControllerに終了を依頼します!」
ViewController.swift「その依頼書受けます!いつでも来やがれ!」

ってな状態にして行きます。


・「私ModalViewControllerはdismissModalプロトコルを持っています!」と宣言

//  ModalViewController.swift

protocol dismissModal {

    func dismiss()

}


class ModalViewController: UIViewController {

    var delegate: dismissModal?


以降、変数delegateはプロトコルを参照するようになります。


・ついでにViewControllerから文字列を受け取るための変数を宣言

//  ModalViewController.swift

protocol dismissModal {

    func dismiss()

}


class ModalViewController: UIViewController {

    var delegate: dismissModal?

    

    @IBOutlet weak var label: UILabel!

    var text: String = ""


今回は、String型変数textを用意しました。

・Labelに変数textをviewDidLoad()で代入

//  ModalViewController.swift

    override func viewDidLoad() {

        super.viewDidLoad()

        label.text = text


        // Do any additional setup after loading the view.

    }


これで、Labelへのデータ受け渡し準備は完了です。


 ・実際に処理を依頼する
モーダルビューの終了は、backボタンで行います。
つまり、backボタンが押されたら、依頼をすればいいですね。

//  ModalViewController.swift

    @IBAction func backToFirst(sender: UIButton) {

        delegate?.dismiss()

    }


オプショナル型にしているのは、
protocolの受け取り先(今回でいうViewController.swift)でdismiss()メソッドが実装されていない場合があるためです。


ここまでで、依頼書を投げるところまでは完了しました。


 
ViewController.swift


次は、受け取る側の処理です。

protocolとは、直訳すると「規約」です。
Javaのinterfaceと同じで、protocol内のメソッドは実装しなければなりません。

受け取った依頼書には、
「dismiss()メソッドを実行してください」と書いてある感じです。
なので、このクラス内でdismiss()メソッドを用意する必要が有ります。


・dismissModalプロトコルを継承

//  ViewController.swift

class ViewController: UIViewController, dismissModal {

 

・継承したprotocol内のメソッド、つまりdismiss()メソッドを実装

//  ViewController.swift

    func dismiss() {

        self.dismissViewControllerAnimated(true, completion: nil)

    } 


・ModalViewControllerの処理の依頼先は自分だ!という宣言

//  ViewController.swift

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        if segue.identifier == "modalSegue" {

            let nextViewController = segue.destinationViewController as! ModalViewController

            nextViewController.delegate = self

        }

    } 


前回のUITableViewControllerでも、遷移先の変数への代入の際に、似た書き方をしました。
今回も復習のために同じことをやるので、

・Segueを通してModalViewController.swiftの変数への代入

//  ViewController.swift

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        if segue.identifier == "modalSegue" {

            let nextViewController = segue.destinationViewController as! ModalViewController

            nextViewController.delegate = self

            nextViewController.text = textField.text ?? "nil"

        }

    }


こうしてしまいましょう。
これで、モーダルビューのDelegate処理が完了しました。
 

キーボードを閉じる処理


残るもうひとつの処理では、
処理を依頼する側=textField
処理を依頼される側=ViewController.swift
となります。

先ほどはプロトコルを作成しましたが、今回はその必要はありません。
すでにtextFieldクラスには、プロトコルが存在しています。

//  UITextField.h
public protocol UITextFieldDelegate : NSObjectProtocol {

    

    @available(iOS 2.0, *)

    optional public func textFieldShouldBeginEditing(textField: UITextField) -> Bool // return NO to disallow editing.

    @available(iOS 2.0, *)

    optional public func textFieldDidBeginEditing(textField: UITextField) // became first responder

    @available(iOS 2.0, *)

    optional public func textFieldShouldEndEditing(textField: UITextField) -> Bool // return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end

    @available(iOS 2.0, *)

    optional public func textFieldDidEndEditing(textField: UITextField) // may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called

    

    @available(iOS 2.0, *)

    optional public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool // return NO to not change text

    

    @available(iOS 2.0, *)

    optional public func textFieldShouldClear(textField: UITextField) -> Bool // called when clear button pressed. return NO to ignore (no notifications)

    @available(iOS 2.0, *)

    optional public func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore.

}


「UITextFieldDelegate」というものです。
これをVIewControllerで継承します。

・UITextFieldDelegateを継承し、viewDidLoad()内で引き受け宣言をする

//  ViewController.swift

class ViewController: UIViewController, dismissModal, UITextFieldDelegate {

    

    @IBOutlet weak var textField: UITextField!


    override func viewDidLoad() {

        super.viewDidLoad()

        textField.delegate = self

        // Do any additional setup after loading the view, typically from a nib.

    }

 
あとは、「キーボードを閉じる」処理を実装すればOKです。


・textFieldShouldReturnメソッドを実装する

//  ViewController.swift

    func textFieldShouldReturn(textField: UITextField) -> Bool {

        textField.resignFirstResponder()

        return true

    }

 

以上で、完了となります。


まとめ


前回のTableViewControllerと似た部分もあったので、
今回は前回よりも簡略化してまとめてみました。 

アウトプットすることで、自分の頭の中も整理されますね。
ちょっと残っていたごちゃごちゃが解消されました!


依頼する側・依頼される側で分けて考えると、
比較的理解しやすいと思います。


はー!ひとつずつ着々と疑問点を解消していこうー!がんばるぞおー!




ちょこひ 

こんばんは!

やっと暖かくなってきて気分がいいちょこひです。

世の中花粉症で死にかけている人が多いですが、
わたしは花粉症ないのでドヤ顔で外に出ています。やったね! 


いろいろ進化したよ!


以前の記事、UITableViewControllerの時に
スクショ乱用しました。

まー、みにくいったらありゃしない。

さすがにまずいぞと思い、Livedoorで綺麗にソースコードを貼る方法を勉強しました。

その結果が、こちら。

public static void main(String[] args) {
System.out.print("Hello, Java!");
}
  みやすーい!凄い!進化した!!!

後ほど、以前の記事もこっちに差し替えます!しばらくお待ちをば!!!


そして、見出しのCSSも導入しました。

こっちの方がかっこいい!
ちょこちょこデザインは変えるかもしれない!

さて。Swift初心者には理解がとっても難しいDelegate。
わたしもその一人。

「そもそもDelegateってなに?」
というところから書いていこうと思います。今回は概念というか、捉え方だけ。



 
Delegateってなに? 


わかりやすくするために、
「ユーザーがメールを送信する」という例を使います。

登場人物
 ①メールを送信する人(Userクラス)
 ②実際に送信処理をするサーバー(Serverクラス)
 ③送信する人がサーバーに送る”送信依頼書"(Protocol)

メールは、ユーザーが直接送るわけではなく、
端末からサーバーを経由します。
実際に送信を行うのはサーバーですよね。
つまり、処理をサーバーに依頼しているわけです。

Delegateとは、処理の名前やメソッド名ではなく、
このように「処理を依頼するデザインパターン」のことです。

ここ、今日までわかっていませんでした。
変数名でdelegate使ったりするし、ごっちゃになっている人は多いかも。


今回の例でいくと、
UserクラスからServerクラスに処理を任せるために、Protocolを通して依頼する
という流れになります。

 
なんでDelegateが必要なの?


「Delegateいらなくね?直接ぶん投げればよくね?」
という疑問を持つ人もいると思います。わたしもそうでした。

一言で言うなら、カプセル化のため。

直接投げてしまうと、システム自体のコードが書き換わってしまう可能性があり、
セキュリティ上あまりよろしくない、らしい。(まだちょっとあやふや)

とりあえず
「カプセル化するためにProtocolを挟まなあかん」
くらいに思っておけばとりあえず大丈夫かと。

ちゃんと理解できたら追記します。


 
テストコード


Delegateがどんなものなのかはひとまずわかったので、
忘れないうちにテストコードを作りました。

このまま続けると少し長くなるので、ソースコードは次回に分けようと思います。


また近々更新します〜!






ちょこひ 

↑このページのトップヘ