

Swift
3では、テーブルビューのセルはコードで作れるのでしょうか。もし可能であれば、テーブルビューの新しいセクションとして作った日付の配列（下記コード該当部分１）に対応するセルをコードで生成するには、どのように書くのかご教示いただけますか。付与するセルは次のとおりです。

[code]

    var checkListItem: [String : Bool] = [ 
        "アイテム1" : false, 
        "アイテム2" : false, 
        "アイテム3" : false, 
        "アイテム4" : false, 
        "アイテム5" : false 
    ] 
    
[/code]

「swift セルをコードで作る」とネットで検索すると、以前のバージョンのコードはありましたがSwift
3では変換してもエラーが出て動きません。本を見てもストリーボードを使うのが前提になっています。

[code]

    import UIKit
    
    class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
        //文字列の日付をDate型に変換するクラス
        class DateUtils {
            class func dateFromString(string: String, format: String) -> NSDate {
                let formatter: DateFormatter = DateFormatter()
                formatter.dateFormat = format
                return formatter.date(from: string)! as NSDate
            }
    
            class func stringFromDate(date: NSDate, format: String) -> String {
                let formatter: DateFormatter = DateFormatter()
                formatter.dateFormat = format
                return formatter.string(from: date as Date)
            }
        }
    
        //テーブルビューのsectionに表示する日付の配列
        var sectionTitle = ["2016-01-23","2015-12-31","2015-01-12","2016-02-21","2016-12-20"]
    
        //今日と日付の配列の最後の日差分の日付を配列にするメソッド
        func getDaysArrayToToday(start:String,max:Int) -> [String] {
            //テーブルビューのsectionに表示する日付の配列の最後の日
            let dateArraymax = sectionTitle.max()
    
            // 日付の配列の最後の日をDate型に変換
            let dateArraymaxdate = DateUtils.dateFromString(string: dateArraymax!, format: "yyyy/MM/dd")
    
            //今日と日付の配列の最後の日差
            let now = NSDate()
            let dateDifference = Int(now.timeIntervalSince(dateArraymaxdate as Date)/60/60/24)
    
            var result:[String] = []
            let formatter = DateFormatter()
            formatter.locale = NSLocale(localeIdentifier: "ja_JP") as Locale
            formatter.dateFormat = "yyyy-MM-dd"
            // 今日
            let todayStr = formatter.string(from: Date())
            let startDate = formatter.date(from: start)!
            var components = DateComponents()
            let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
    
            for i in 0 ..< max {
                components.setValue(i,for: Calendar.Component.day)
                let wk = calendar.date(byAdding: components, to: startDate)!
                let wkStr = formatter.string(from: wk)
                print(max)
                if wkStr > todayStr {
                    break
                } else {
    
                    result.append(wkStr)
                }
                    let sectionTitle2 = getDaysArrayToToday(start: dateArraymax!,max: dateDifference)
    
                //今日と日付の配列の最後の日差分の日付配列を元の日付配列に加える
                sectionTitle.append(contentsOf: sectionTitle2)//該当部分１
            }
            return result
        }
    
        //今日と日付の配列の最後の日差分の日付配列をテーブルビューのsectionに表示する
        func numberOfSections(in tableView: UITableView) -> Int // Default is 1 if not implemented
        {
            return sectionTitle.count
        }
        ////
        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? // fixed font style. use custom view (UILabel) if you want something different
        {
            return sectionTitle[section]
        }
    
        let statusBarHeight = UIApplication.shared.statusBarFrame.height
    
    //セクションの項目
    
        // チェックリストの項目とチェック状態
    
        var checkListItem1: [String : Bool] = [
            "アイテム1" : true,
            "アイテム2" : false,
            "アイテム3" : true,
            "アイテム4" : true,
            "アイテム5" : false
        ]
        var checkListItem2: [String : Bool] = [
            "アイテム2-1" : false,
            "アイテム2-2" : true,
            "アイテム2-3" : true,
            "アイテム2-4" : true,
            "アイテム2-5" : false
        ]
        var checkListItem3: [String : Bool] = [
            "アイテム3-1" : true,
            "アイテム3-2" : true,
            "アイテム3-3" : true,
            "アイテム3-4" : true,
            "アイテム3-5" : false
        ]
        var checkListItem4: [String : Bool] = [
            "アイテム4-1" : true,
            "アイテム4-2" : false,
            "アイテム4-3" : true,
            "アイテム4-4" : false,
            "アイテム4-5" : false
        ]
        var checkListItem5: [String : Bool] = [
            "アイテム5-1" : true,
            "アイテム5-2" : false,
            "アイテム5-3" : true,
            "アイテム5-4" : true,
            "アイテム5-5" : true
        ]
    
        // 
        var tableData: [[String: Bool]] = []
    
        let tableView = UITableView()
    
        //
        override func viewDidLoad() {
            super.viewDidLoad()
    //    sectionを日付降順にソートする
            sectionTitle = sectionTitle.sorted { $0 > $1 }
    
            tableData = [checkListItem1, checkListItem2, checkListItem3, checkListItem4, checkListItem5]
    
            // UITableView の作成
            tableView.frame = CGRect(
                x: 0,
                y: statusBarHeight,
                width: self.view.frame.width,
                height: self.view.frame.height - statusBarHeight
            )
            tableView.delegate = self
            tableView.dataSource = self
            self.view.addSubview(tableView)
        }
    
        // セルの作成
        //
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            // tableDataの中から抽出
            let sectionData = tableData[indexPath.section]
    
            // キーで並び替え
            let keys = sectionData.keys.sorted()
    
            // キーの文字列を取得
            let cellText = keys[indexPath.row]
    
            // セルの作成とテキストの設定
            let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
            cell.textLabel?.text = cellText
    
            ///
            let cellIscheckd = sectionData[cellText]
    
            // チェック状態が true なら、初めからチェック状態にする
            if cellIscheckd == true {
                cell.imageView?.image = UIImage(named: "checked")
            } else {
                cell.imageView?.image = UIImage(named: "unchecked")
            }
    
            return cell
        }
    
        // セルがタップされた時の処理
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            if let cell = tableView.cellForRow(at: indexPath) {
                // タップしたセルのテキストを取得
                let cellText = cell.textLabel?.text ?? ""
    
                // 画像を切り替えと Dictonary の値を変更
                if cell.imageView?.image == UIImage(named: "checked") {
    
                    self.tableData[indexPath.section][cellText] = false
    
                    cell.imageView?.image = UIImage(named: "unchecked")
                } else {
                    self.tableData[indexPath.section][cellText] = true
                    cell.imageView?.image = UIImage(named: "checked")
                }
                // 選択状態を解除
                cell.isSelected = false
            }
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            let sectionData = tableData[section]
            return sectionData.count
        }
    }
    
[/code]


CC BY-SA 3.0
2016-12-28T15:13:40.180
31501
2017-06-02T01:09:36.167
2017-03-08T14:52:36.647
76
19879
question
swift3
テーブルビューセルをコードから生成するには


`UITableView`を使いこなすには、つぎのAppleの文書で学習してください。

[iOS Table View
プログラミングガイド](https://developer.apple.com/jp/documentation/TableView_iPhone.pdf)（PDF書類）  
[Table View Programming Guide for
iOS](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/TableView_iPhone/AboutTableViewsiPhone/AboutTableViewsiPhone.html)（英語原文）

2013年で、情報として古い、サンプルコードがObjective-
Cであるとか、今となってはマイナス面だけ目立ちますが、`UITableView`を扱うのに必須な情報が凝縮されているので、骨は折れますが、ぜひ一読ください。  
この文書から、ふたつのエッセンスをあげておきます。ひとつは、`UITableView`は、 **MVCデザインパターン**
に基づいて設計されているという点。もうひとつは、`UITableViewCell`は **再利用して使う** という点です。

* * *

## MVCデザインパターン

これはAppleやiOSフレームワーク独自の概念ではなく、オブジェクト指向、GUIアプリケーション開発における、広く知られたデザインパターン（設計様式）で、Wikipediaにも載っていますので、そちらも一読ください。「MVC」は、Model（データ）-
View（ビュー）-
Controller（制御部）の頭文字をとったものです。抽象的な概念で、解釈に幅がありますが、iOSフレームワークに即して説明すると、「データとビューを一緒にせず、たがいに独立して扱う」ことに主眼があります。さらに`UITableView`に即していえば、「テーブルの中で、データを編集したりしない」ということです。

* * *

## UITableViewCellは再利用する

テーブルは、セルを行に並べるという構成になっています。100行のデータがあれば、100個のセルが並び、10000行のデータがあれば、10000個のセルが並ぶ……というふうにしていくと、いわゆる「処理が重たい」プログラムになってしまいます。じっさいを考えてみると、10000行のテーブルなんて、たいして珍しくもありません。そこでセルを再利用することで、セルの総数を減らす仕組みを`UITableView`は採用しています。たとえば画面上に10行見えているテーブルには、10＋α個のセルしかありません。  
では、具体的にどういうコードを記述するのか、説明します。  
まず、再利用する`UITableViewCell`（ないし、そのサブクラス）を登録します。

[code]

    let cellIdentifier = "Cell"
    override func viewDidLoad() {
        super.viewDidLoad()
        // Table View Cellの登録
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
    }
    
[/code]

つぎの`UITableViewDataSource`のメソッド内で、セルの再利用を実行します。

[code]

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
    
        return cell
    }
    
[/code]

* * *

以上が、ご質問である「テーブルビューセルをコードから生成するには」に対する回答です。「`register`で登録して、`dequeueReusableCell`で再利用」と覚えるといいでしょう。  
おまけで、セルの再利用をしたサンプルコードを載せてきます。ご掲示のサンプルコードを、改善したものを載せたかったのですが、誰でもありがちだと思いますが、コードに目を通している間に、頭の中が真っ白になりかけまして、しかたなく、外見似たようなテーブルになるコードを仕上げました。

_プログラムの概要_

  1. 5日前から今日までの6日間をセクションとする。
  2. セクションごとに5つの項目を並べる。
  3. 項目には、`checked`、`unchecked`の画像どちらかをランダムに表示する。

* * *
[code]

    import UIKit
    
    class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        // Table View Cellの識別子
        let cellIdentifier = "Cell"
        // Table DataのKey値
        let dateKey = "Date"
        let titleKey = "Title"
        let contentKey = "Contents"
        let itemKey = "Item"
        let checkedKey = "Checked"
    
        var tableView: UITableView!
        var checkedImage: UIImage!
        var uncheckedImage: UIImage!
    
        // Model
        var tableData = [[String : Any]]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Table Viewの生成
            tableView = UITableView()
            tableView.dataSource = self
            tableView.delegate = self
            view.addSubview(tableView)
            // Table ViewのConstraint設定
            tableView.translatesAutoresizingMaskIntoConstraints = false
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20.0).isActive = true
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
            // Table View Cellの登録
            tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
    
            // Imageの生成
            checkedImage = UIImage(named: "checked")
            uncheckedImage = UIImage(named: "unchecked")
    
            // Model（tableData）を作成
            // 5日前から今日までの日付をタイトルにして、6セクションを生成
            let formatter = DateFormatter()
            formatter.timeZone = TimeZone(abbreviation: "JST") ?? TimeZone.current
            formatter.dateFormat = "YYYY-MM-dd"
            var calendar = Calendar(identifier: .gregorian)
            calendar.timeZone = formatter.timeZone
            let today = Date()
            // セクションごとのコンテンツを生成し、格納
            for i in -5..<1 {
                var content = [[String : Any]]()
                for j in 0..<5 {
                    var dayItem = [String : Any]()
                    dayItem[itemKey] = String(format: "Item %d - %d", i + 6, j + 1)
                    dayItem[checkedKey] = (arc4random_uniform(2) == 0) ? false : true
                    content.append(dayItem)
                }
                var section: [String : Any] = [contentKey : content]
                // -i日前のDateを取得
                if let theDay = calendar.date(byAdding: .day, value: i, to: today) {
                    section[dateKey] = theDay // Date型で格納
                    section[titleKey] = formatter.string(from: theDay) // 文字列型で格納
                } else {
                    section[dateKey] = Date()
                    section[titleKey] = ""
                }
                tableData.append(section)
            }
        }
    
        // セクションの個数を指定
        func numberOfSections(in tableView: UITableView) -> Int {
            return tableData.count
        }
    
        // セクションごとの行数を指定
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return (tableData[section][contentKey] as! [Any]).count
        }
    
        // セクションのタイトルを指定
        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
            return tableData[section][titleKey] as? String
        }
    
        // セルのコンテンツを指定
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
    
            if let content = tableData[indexPath.section][contentKey] as? [[String : Any]] {
                if let itemName = content[indexPath.row][itemKey] as? String {
                    cell.textLabel?.text = itemName
                }
                if let checked = content[indexPath.row][checkedKey] as? Bool {
                    cell.imageView?.image = checked ? checkedImage : uncheckedImage
                }
            } else {
                cell.textLabel?.text = ""
                cell.imageView?.image = uncheckedImage
            }
    
            return cell
        }
    
    }
    
[/code]

※テーブルのレイアウトには`NSLayoutConstraint`を使いましょう。画面を縦にしても横にしても、テーブルのレイアウトが保持されます。

※MVCのModelであるデータ（`tableData`）は、こういう構造にしています。

[code]

    [
        [
            "Title": "2016-12-24",
            "Date": 2016-12-24 09:30:19 +0000,
            "Contents": [
                ["Item": "Item 1 - 1", "Checked": true],
                ["Item": "Item 1 - 2", "Checked": false],
                ["Item": "Item 1 - 3", "Checked": false],
                ["Item": "Item 1 - 4", "Checked": false],
                ["Item": "Item 1 - 5", "Checked": false]
            ]
        ],
        .........
    ]
    
[/code]

これは、`PropertyListSerialization`クラスを使って、書き出すと、そのまま **PropertyList**
形式の書類になります。逆にいうと、PropertyListの書類を読み込むと、このデータ構造になります。PeropertyList形式は、アプリケーションの初期設定ファイル（info.plist）にも採用されるなど、Appleの世界では、広く利用されるデータ形式です。

※日付の処理には、`Date`、`DateFormatter`に加え、`Calendar`を使うと、よりきめ細かい処理が可能になります。それと、日付、時刻の処理をするとき、時間帯の設定（`TimeZone`）をお忘れなく。

[![画像の説明をここに入力](https://i.stack.imgur.com/giif6.png)](https://i.stack.imgur.com/giif6.png)


CC BY-SA 3.0
2016-12-29T11:33:14.670
31530
2016-12-29T11:33:14.670
18540
31501
answer