

下記のようなコードで、APIからjsonを取得し、それを配列に格納しました。

**SWIFTコード**

[code]

    var movieList: [[String: AnyObject]] = []
    
    func sample() {
            Alamofire.request(.GET, "http://123456789").validate().responseJSON { response in
                switch response.result {
                case .Success:
                    if let value = response.result.value {
                        let json = JSON(value)
    
                        for (key, _):(String, JSON) in json["movies"] {
                            for (key2, _):(String, JSON) in json["movies"][key] {
                                for (_, subJson3):(String, JSON) in json["movies"][key][key2] {
                                    let movieList: [String: AnyObject] = [
                                        "id": subJson3["id"].int!,
                                        "title": subJson3["title"].string!,
                                        "published_year": subJson3["published_year"].string!
                                    ]
                                    self.movieList.append(movieList)
                                }
                            }
                        }
                        self.tableView.reloadData()
                    }
                case .Failure:
                    print("情報を取得できませんでした。")
                }
            }
    }
    
[/code]

**JSONデータ**

[code]

    {
      "movies" : {
        "2015" : {
          "1" : [
            {
              "id" : 111,
              "title" : "タイトル1",
              "published_year" : "2015",
            }
          ],
          "6" : [
            {
              "id" : 222,
              "title" : "タイトル2",
              "published_year" : "2015",
            }
          ]
        },
        "2008" : {
          "3" : [
            {
              "id" : 333,
              "title" : "タイトル3",
              "published_year" : "2008",
            },
            {
              "id" : 444,
              "title" : "タイトル4",
              "published_year" : "2008",
            }
          ],
        },
        "2016" : {
          "1" : [
            {
              "id" : 555,
              "title" : "タイトル5",
              "published_year" : "2016",
            },
            {
              "id" : 666,
              "title" : "タイトル6",
              "published_year" : "2016",
            }
          ]
        }
      }
    }
    
[/code]

**movieListの配列データの中身**

[code]

    var movieList: [[String: AnyObject]] = [["id": 111, "title": タイトル1, "published_year" : 2015], ["id": 222, "title": タイトル2, "published_year" : 2015], ["id": 333, "title": タイトル3, "published_year" : 2008], ["id": 444, "title": タイトル4, "published_year" : 2008], ["id": 555, "title": タイトル5, "published_year" : 2016], ["id": 666, "title": タイトル6, "published_year" : 2016]]
    
[/code]

このデータからtableViewを年ごとのsectionに分けて、titleをrowに格納することは可能でしょうか？  
要するに下記の画像のようにしたいです。

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

もしくは、下記のような辞書型を作った方が良いのでしょうか？

[code]

    var movieList: [String: [String: AnyObject]] = [
    2015: [["id": 111, "title": タイトル1, "published_year" : 2015], ["id": 222, "title": タイトル2, "published_year" : 2015]], 2008: [["id": 333, "title": タイトル3, "published_year" : 2008], ["id": 444, "title": タイトル4, "published_year" : 2008]], 2016: [["id": 555, "title": タイトル5, "published_year" : 2016], ["id": 666, "title": タイトル6, "published_year" : 2016]]
    ]
    
[/code]

どういった配列 or
辞書型を作れば、添付画像のようなtableViewを作成することができるのでしょうか。100年分くらいのデータがありますので、変数を100年分作成するのは避けたいと思っております。


CC BY-SA 3.0
2016-09-02T12:52:32.650
28655
2016-09-03T00:14:33.290
2016-09-02T18:35:35.373
18679
18679
question
swift ios
最適な配列 or 辞書型を作成して、添付画像のようなtableViewを作成したい


あなたが提示されたJSONデータをそのままSwiftのデータ型で表すとこんな感じでしょうか。

[code]

    let jsonObject: [String: [String: [String: [[String: AnyObject]]]]] = [
        "movies" : [
            "2015" : [
                "1" : [
                    [
                        "id" : 111,
                        "title" : "タイトル1",
                        "published_year" : "2015",
                    ]
                    //,...
                ]
                //,...
            //,...
        ]
    ]
    
[/code]

あまりにも入り組んでいて、さすがにこれをそのまま使う気にはならないですね。

しかし、あなたの書かれた2つの例:

[code]

    var movieList: [[String: AnyObject]]
    
[/code]

こちらはsection情報を毎回再構成しないといけません。

[code]

    var movieList: [String: [String: AnyObject]]
    
[/code]

の方は、

[code]

    var movieList: [String: [[String: AnyObject]]]
    
[/code]

の書き間違いだと思いますが、sectionごとにデータが束ねられているものの、一番外側のデータ型である`Dictionary`は順序非保存なので、これまた毎回表示したい順序になるようにデータを並べ替えないといけません。例示されたデータ型が間違っていたように、このレベルまで階層構造が深くなると一体どの階層のどのデータにアクセスしているのかもわからなくなりがちです。

ここはタイトルの「最適な配列 or
辞書型」と言う記述には反するかもしれませんが、あなたのアプリがしようと思っていることに最適のデータ構造を定義された方が、全体としてみるとコードの方もシンプルにできます。

少々まどろっこしいように思えるかもしれませんが、次のような2つのデータ型を準備しておきます。

[code]

    struct Movie: CustomStringConvertible {
        var id: Int
        var title: String
        var publishedYear: String
    
        init(json movieItem: JSON) {
            self.id = movieItem["id"].int!
            self.title = movieItem["title"].string!
            self.publishedYear = movieItem["published_year"].string!
        }
    
        //デバッグ用
        var description: String {
            return "<Movie: \(id):\(title)(\(publishedYear))>"
        }
    }
    
    struct MovieSection: CustomStringConvertible {
        var header: String
        var movies: [Movie]
    
        init(header: String, json yearlyMovies: JSON) {
            self.header = header
            var movies: [Movie] = []
            for (_, monthlyMovies) in yearlyMovies {
                for (_, movie) in monthlyMovies {
                    movies.append(Movie(json: movie))
                }
            }
            self.movies = movies
        }
    
        //デバッグ用
        var description: String {
            return "<MovieSection: \(header)\n\(movies))>"
        }
    }
    
[/code]

上のデータ型を使ってインスタンス変数としてこんなものを用意しておきます。

[code]

    var movieSections: [MovieSection] = []
    
[/code]

そうすると、この配列にデータを入れる部分はこんな風に書けます。

[code]

        case .Success(let value):
            let json = JSON(value)
            for (year, section) in json["movies"].sort({$0.0 > $1.0}) {
                self.movieSections.append(MovieSection(header: "\(year)年", json: section))
            }
    
[/code]

いかがでしょうか。随分とスッキリするとは思いませんか。

あなたが提示された`UITableView`の画面を実現するには、`UITableViewDataSource`の以下の4つのメソッドを実装する必要があるわけですが、こちらもかなりスッキリさせることができます。

[code]

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return movieSections.count
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movieSections[section].movies.count
    }
    
    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return movieSections[section].header
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        let movie = movieSections[indexPath.section].movies[indexPath.row]
        cell.textLabel?.text = movie.title
        return cell
    }
    
[/code]

Swiftの`Dictionary`に相当するデータ構造は、ちょっとした構造のあるデータを手軽に表現できるのでつい多用しがちなのですが、長く保持されるデータ、頻繁に参照されるデータに使う場合には、かえって使いづらくなってしまうことも多いです。

問題領域に最適なデータ構造を定義することでプログラム全体をスッキリさせることができます。ぜひお試しください。


CC BY-SA 3.0
2016-09-02T23:53:41.020
28660
2016-09-03T00:14:33.290
2016-09-03T00:14:33.290
13972
13972
28655
answer