質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

解決済

2回答

5458閲覧

swiftのUICollectionViewの更新

etemon

総合スコア19

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

0クリップ

投稿2016/03/13 08:28

swift入門者です。今サーバーのデータベースの情報をUICollectionViewCellに持ってくる作業をやっているのですが。なぜかうまくいきません。下のコードでは問題なく動くのですが、、、

import UIKit class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { @IBOutlet weak var myCollectionView: UICollectionView! var articleArray:[Dictionary<String,String>] = [] override func viewDidLoad() { super.viewDidLoad() accessJSON() } /*===========================セル==================================*/ //セルの数 func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return articleArray.count } //セルの内容 func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! MyCollectionViewCell cell.myLabel.text = articleArray[indexPath.item]["title"] return cell } /*============================データベース=================================*/ func accessJSON(){ let urlStr = "自分のURL" if let url = NSURL(string: urlStr) { let urlSession = NSURLSession.sharedSession() let task = urlSession.dataTaskWithURL(url, completionHandler: self.getJSON) task.resume() } } func getJSON(data: NSData?, res: NSURLResponse?, error: NSError?){ do { let jsonArray = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray for (var i=0; i<jsonArray.count; i++) { var articleDic:[String:String] = [:] if let id = jsonArray[i]["id"] as? String{ articleDic["id"] = id } if let title = jsonArray[i]["title"] as? String{ articleDic["title"] = title } if let image = jsonArray[i]["image"] as? String{ articleDic["image"] = image } articleArray.append(articleDic) } dispatch_async(dispatch_get_main_queue()){ print(self.articleArray) self.myCollectionView.reloadData() } } catch { print("エラー") } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

上のコードでは問題なく動くのですが、コードが複雑になってデータベースからJSONの情報を取ってくる部分だけをModel.swiftにまとめようとしたとき、UICollectionViewが更新されないです(やろうとしていることは上と同じです)。エラーが出るのは下のコードです。
Model.swift

import UIKit class Model: NSObject { var articleArray: [Dictionary<String,String>] = [] func accessJSON(){ let urlStr = "http://steins-t.com/kuchiren5/api.php?json" if let url = NSURL(string: urlStr) { let urlSession = NSURLSession.sharedSession() let task = urlSession.dataTaskWithURL(url, completionHandler: self.getJSON) task.resume() } } func getJSON(data: NSData?, res: NSURLResponse?, error: NSError?){ do { let jsonArray = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray for (var i=0; i<jsonArray.count; i++) { var articleDic:[String:String] = [:] if let id = jsonArray[i]["id"] as? String{ articleDic["id"] = id } if let title = jsonArray[i]["title"] as? String{ articleDic["title"] = title } if let image = jsonArray[i]["image"] as? String{ articleDic["image"] = image } articleArray.append(articleDic) } dispatch_async(dispatch_get_main_queue()){ let hoge = ViewController() //↓ここでエラーが出る!!! hoge.myCollectionView.reloadData() } } catch { print("エラー") } } }

ViewController.swift

import UIKit class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { @IBOutlet weak var myCollectionView: UICollectionView! //var articleArray:[Dictionary<String,String>] = [] override func viewDidLoad() { super.viewDidLoad() //Modelクラスのオブジェクトを作ってaccessJSONプロパティを実行 let model = Model() model.accessJSON() } /*===========================セル==================================*/ //セルの数 func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 8 } //セルの内容 func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! MyCollectionViewCell cell.myLabel.text = "テスト" return cell } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

なにか良い方法はないのでしょうか?みなさんの知恵をぜひお借りしたいです(>.<);;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

let hoge = ViewController()
を実行すると、現在表示されているViewControllerとは別の新しいViewControllerが生成されてhogeに代入されます。さらにその新しいViewConrtrollerはstoryboardで配置した部品もロードされていませんからhogeのmyCollectionViewはnilです。このため、reloadData()がエラーになったのだと思います。

本来やりたかったのは、新しいViewControllerを生成するのではなく、現在表示されているViewControllerのmyCollectionViewの表示を更新したかっただけのはずです。

こういう時は、ModelにJSONデータの取得を依頼(accessJSON呼び出し)した時に、呼び出し元のViewConrtrollerにデータ取得の完了を教えてもらえるようなインターフェースを作れば良いです。そしてその通知をもらってViewControllerの中でreloadDataすればよいです。
NCC1701さんも指摘していますが、モデルの中でビューを操作すべきではありません。

呼び出し元に完了通知するインターフェースを作る方法はいくつかあります。
http://sakebook.hatenablog.com/entry/2015/08/12/133756
とかを読んで勉強してください。
私としては、ここではクロージャを使用することをお勧めします。クロージャをマスターしておくと、今後別の場面への応用もしやすいと思います。


あと、ついでに指摘しておくと、ViewController.swiftのviewDidLoadで
let model = Model()
としていますが、このmodel変数はローカル変数のため、viedDidLoadを終了すると消滅します。これに伴い、もし他にこのモデルオブジェクトを参照している変数がなければ、モデルオブジェクト自体も消滅します。
今はnumberOfItemsInSectioncellForItemAtIndexPathの実装が仮コーディング状態なので別に困ってないのだと思いますが、ちゃんとコーディングするなら、これらの関数の中でモデルにアクセスしてモデルの内容を取り出す処理が必要です。
そのために少なくともmodelはViewControllerのプロパティとして定義する必要があります。

投稿2016/03/14 04:55

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

エラーメッセージが不明のため,想像です。

ViewControllerからmodel.accessJSON()を呼び出し,そのmodelの中で呼び出している

let hoge = ViewController()

hoge.myCollectionView.reloadData()

は循環参照になってませんか(あるいはdeallocされてない?)?

Swift

1let model = Model() 2model.accessJSON() 3self.myCollectionView.reloadData()//追加

reloadData()をする場所を変えて試してみてください。

なお,MVCの観点からModelクラスがControllerクラスの振る舞いを操作するのはあまり良くないように思えます。(ModelがViewControllerのmyCollectionView.reloadData()というメソッドを実行している)極端な言い方をすると,Modelクラスは「値は返してやるが,その後その値をもとにして何するのかは知らん。興味もない」みたいな態度をとるオブジェクトの設計で良いと思います。

投稿2016/03/13 15:26

NCC1701

総合スコア1680

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問