こんにちは!

通う学校の体験入学補助スタッフを終えて、
近所のカフェで相変わらずのドヤリング。

プログラミングがひと段落したので、
気晴らしも兼ねて更新。


みんな大好きTableView!


さて。Obj-Cのものが着々とSwiftに移行されていますね。
わたしはObj-Cは書けません。初っ端からSwiftを学んでいます。
まだ珍しい部類・・・なのかな?

まだまだド初心者だった頃にSwift2.0が来て、
あっぷあっぷしながらも何とか乗り越えた思い出。
コツというか、流れを一度理解すると書きやすい気がします、Swiftは。


初心者は必ずと言っていいほどはまる」UITableViewController。

わたしも見事にすっぽりしました。

今回も覚書がてら、
格闘の軌跡をまとめておきます。




【注意】
・livedoorでのソースコードの記載がめんどくさかったわからなかったので
 全てスクリーンショットでお届けします。見にくいと思う。お許しをば。
・わたしのクラスメートたちにわかりやすいようにまとめるので
 ちょっと偏りがあるかもしれないです。
・右往左往してますが微笑ましく見てください。


【16/04/11追記】
スクショを全て文字に差し替えました!


テストコード


今回は

UIViewController上のボタン
→UITableVIewController上のセル
→UIVIewController(詳細画面的な?)


という流れで作ってみます。

データは全てローカル。
動けばよかろう精神。
(サーバーまだわかんないだけです)


行くぞオラ


①View先に全部置いちゃう

NavigationControllerについて(個人解釈)
 storyBoardではVIewのように表示されますが、実機ではみることができません。
 いろんなViewたちの管理をするお偉いさん的ポジション。
 NavigationController下にいるViewには、画面上部に戻るボタンが自動で入ります。便利。


storyBoard上のUIViewControllerを選択した状態で、
ツールバーの「Editor」→「Embed in」→「Navigation Controller」を選択。

chooseNavigationController


すると、左側にグレーのNavigationControllerが追加され、
画面上部に戻るボタン用の枠が用意されます。

これでこのVIewはNavigationControllerの支配下に入りました。たぶん。

便利なのは、このViewからSegueで画面遷移を指示すると、
自動で新しいViewもNavigationControllerの支配下に入ること。

基本的にEmbed inでNavigationControllerをぶっこんだ方が楽っぽい。




次のViewのUITableViewControllerを配置。
この状態ではまだsegueを繋いでいないので、TableView上部にはスペースがありません。
putTableView
最初のViewに適当にボタンを置いて、TableViewControllerにsegueをつなぎます。
control + ドラッグで、ぐわーーーーっと。
ここでは「Show」を選択。

chooseShowSegue

無事segueが繋がると、TableViewControllerの上部にも
戻るボタン用のスペースが確保されます。


toTableViewSegue



新しくUIViewControllerを設置。
TableViewのCellがタップされた際に詳細画面(UIVIewController)に飛ぶようにするので
TableViewCellと新しく置いたViewをsegueでばーーんします。

詳細画面のほうのView(DetailViewと呼びます)の真ん中に適当にlabelを設置。
文字は変更なし。あえてしません!


②各Viewが参照するクラスのファイルを新規作成

左側のフォルダがぶわーってなってるところ(名前ど忘れ)の、
ViewController.swiftなどがあるすぐ上のフォルダを右クリックし、
New File...」を選択。


chooseNewFile


iOS > Source から、「Cocoa Touch Class」を選択。


chooseCocoaTouch


なんでSwift Fileじゃないの?
 Swift Fileでももちろん作れます。
 ですが、CocoaTouchはViewの型を指定してあげるだけで必須のメソッドをあらかじめ用意してくれます。CocoaTouchの方がミスも少ないし、何より楽ちん!


まずはTableViewControllerが参照するクラスを作るので、
型を「UITableViewController」を選択。

型を選択すると、class: の部分にも型名が自動で入ります。
補足する場合はclass:の部分を変更します。
今回はTableViewは一つだけなので、そのまま。

makeFileTableView


DetailViewが参照するclassも、同様に作成。

makeFileDetail

ViewControllerは2つあるので、

先頭に「Detail」を追加して判別しています。





③storyBoardのパーツとクラスのファイルを紐付け

これで各Viewが参照するクラスファイルは作成されたので、
ソースコードとstoryBoardの紐付けをします。

storyBoardに戻り、VIewControllerを選択した状態で、
画像の部分を参照先のクラスに設定。(カスタムクラス)

このViewはデフォルトで存在しているViewController.swiftをそのまま利用します。


customClassView


同様に、TableController、DetailVIewも設定。



customClassTableView

detailCustomClass

これで各Viewと各classが紐付けられました。





④紐付けたソースコードをいじくる

ViewController.swiftは変更点がないので割愛します。

まずはTableViewController.swift。


//  TableViewController.swift

import UIKit


class TableViewController: UITableViewController {

    

    override func viewDidLoad() {

        super.viewDidLoad()

       

        // Uncomment the following line to preserve selection between presentations

        // self.clearsSelectionOnViewWillAppear = false


        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.

        // self.navigationItem.rightBarButtonItem = self.editButtonItem()

    }

    

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }



デフォルトではこうなっているはず。

・viewDidLoad()
 →Androidでいう「onCreate()」みたいなもんです。
  立ち上がったときに一番最初に通過するメソッド。
・didReceiveMemoryWarning()
 →メモリーがアレしたときにアレするアレ



続いて、テーブルの行数・列数を設定するメソッドがあります。

//  TableViewController.swift

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

        // #warning Incomplete implementation, return the number of sections

        return 1    //  デフォルトは0

    }


    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        // #warning Incomplete implementation, return the number of rows

        return cellData.count

    }



・numberOfSectionsInTabView(なんたら)
 →テーブルの列数。縦分割のアレ。基本的に1です。デフォルトは0
・tableView(なんたら、numberOfRowsInSection section: Int)
 →テーブルの行数。数値で固定してもいいし、変数にして間接的に指定してもいい。デフォルトは0


行数はデータ数に合わせてほしいので、
練習も兼ねて、

テーブルに入れるデータはソースコード内の配列から
引っ張ってくるようにしました。


//  TableViewController.swift

import UIKit


class TableViewController: UITableViewController {

    var cellData: [String] = [String]()     //  セルに入れるデータ格納用配列

    

    

    //  Androidでいう「onCreate」的な。

    //  AndroidintentgetIntent()にあたるものもviewDidLoad()に書く。

    override func viewDidLoad() {

        super.viewDidLoad()

        

        cellData.append("あいうえお")

        cellData.append("かきくけこ")

        cellData.append("さしすせそ")

   


空のString配列cellDataを作成し、
viewDidLoad()で要素を追加しています。

つまり、TableViewが立ち上がったときに
cellDataには3つの要素が含まれていることになります。



では実際に、cellに要素をぶん投げましょう。
ぶん投げ先のcellのIdentifier(Androidでいうid)が必要なので、設定します。


storyBoard上でcellを選択した状態で、

cellIdentifier

今回は「tableCell」というIdentifierを設定。


TableViewController.swiftに戻り、

tableView(tableView: UITableView, なんたら)

のコメントアウトを外します。

//  TableViewController.swift

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath)


        cell.textLabel?.text = cellData[indexPath.row] ?? "nil"


        return cell

    }




"tableCell"の部分を先ほど設定したIdentifierに書き換えます。
ここがあっていないとcellにデータがぶん投げられないので注意。
ハマりやすいポイント(個人的感想)


let cellには"tableCell"というIdentifierを持つセルへのインスタンスが格納され
cell.textLabel?.text に配列cellDataの行数番目のindexをぶっ込む・・・
語彙のなさに絶望。伝わってください。


これでセルへのデータぶん投げは完了。



TableViewController.swiftでもうひとつチャレンジ。
一番下の方にある「propareForSegue」というメソッドの
コメントアウトを外し、


//  TableViewController.swift

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

        let nextView = segue.destinationViewController as! DetailViewController

        nextView.segueText = "Swift"

    }



このように書き換えます。

destinationViewController は、直訳すると「つながったViewController」。
つまり遷移先です。
遷移先のViewが参照しているクラスにキャストして、
ソースコード同士をつなげるイメージ。


nextViewには、次のVIewが参照するクラスへのパスが格納されてる(きっと)
nextView.segueText = "Swift" は、
遷移先のViewが参照しているクラスの変数segueTextに"Swift”を代入してね
ということになります。


つまり!
DetailViewController.swiftに変数segueTextを用意する必要が有ります。
クラスを超えてデータを渡す場合は、一度変数で受け取ってから
各パーツにセットしないといけない。らしい。


connectLabel


まずはstoryBoardに戻り、DetailViewのLabelを
DatailViewController.swiftに紐付けます。
今回はそのまま「label」という名前にしました。


その後、DatailViewController.swiftに変数segueTextを作成。

//  DetailViewController.swift

import UIKit


class DetailViewController: UIViewController {

    

    @IBOutlet weak var label: UILabel!

    var segueText: String = ""  //  初期化しないとエラーになる




TableViewからのsegueにより、変数segueTextは空文字列から
"Swift"に変わります。


あとは、viewDidLoadでlabelにsegueTextを代入してあげれば・・・

//  DetailViewController.swift

import UIKit


class DetailViewController: UIViewController {

    

    @IBOutlet weak var label: UILabel!

    var segueText: String = ""  //  初期化しないとエラーになる


    override func viewDidLoad() {

        super.viewDidLoad()

        label.text = segueText


        // Do any additional setup after loading the view.

    }




完成!!!



33


39


43

簡単にではありますが
以上が私なりの解説。

解説って本当にいい勉強方法ですよね。
自分がわかっていないところが浮き彫りになって。

この記事の執筆に2時間半かかっています。
あああ、頑張った・・・


そのうち見やすいように書き換えるかもしれないです。
眠たい・・・




ちょこひ