• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:Swiftについて教えてください)

SwiftでALAssetをUICollectionViewで表示する方法

このQ&Aのポイント
  • カメラロールにある写真をUICollectionViewに読み込み表示させる方法を調べてみましたが、わかりませんでした。
  • ALAssetを使用してUICollectionViewで画像を表示する方法について教えてください。
  • SwiftでALAssetをUICollectionViewで表示するためのコード例や参考資料がありますか?

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

掲載していただいたコードを検証してみましたが、大きな問題が2つあると思います。 まず、self.groups.enumerateAssetsUsingBlockのgroupsは、ALAssetsGroup()で初期化しただけで使っていますが、ここは、enumerateGroupsWithTypesで取得したグループを使う必要があります。 swiftでALAssetLibraryを使った例はあまりないので、Objective-Cの例になりますが、 http://dev.classmethod.jp/smartphone/iphone/assetslibrary/ のloadAssetsLibraryをお手本にして、これをswiftに変換して使用するとよいと思います。 もう1つの問題は、enumerateAssetsUsingBlockは非同期に実行されるので、この処理をviewDidLoadに書いても実際に実行されるのは、numberOfItemsInSectionの実行より後になるはずです。すると、self.assets.countの値は0なので、numberOfItemsInSectionの返却値も0となり、何も表示されないことになります。この問題はself.assets.insertObjectとnumberOfItemsInSectionを実行する箇所でログを取ってみるとよくわかると思います。 1個目の問題で紹介した参考サイトでは、loadAssetsLibraryの実行を「一覧表示をしたい画面の一つ前の画面に挟み込むと良い」と書いていますが、もしそういうタイミングを取るのが難しければ、insertObjectすると同時にコレクションビューに対してreloadData()を実行してもよいと思います。そうすれば、insertObjectするたびにコレクションビューが最新の状態に更新されるはずです。

dkong
質問者

お礼

回答ありがとうございます。一つ目の問題は、教えていただいたサイトを参考にしたり、その他のいろいろ調べて補足コメントのようにしてクリアできました。assetを取得することができるようになりました。二つ目の問題がクリアできず困っています。補足コメントに追加質問させてください。

dkong
質問者

補足

二つ目の部分ですが、ご指摘いただいたようにログを取ってみるとself.assets.countの値は0で、その後にself.assets.countの値が取得されてます。 self.assets.addObject(asset!) self.collectionView!.reloadData() としたのですが、Cannot invoke 'reloadData' with no argumentsというエラーがでます。引数なしでは関数を実行出来ないというエラーということはわかったのですが、どんな引数が必要か分かりません。 swift UICollectionView reloadDataで検索をしてみたのですが、引数についてよく分かりませんでした。 @IBOutlet weak var collection:UICollectionView!としてみたら、エラーが消えたのですが、アプリが落ちてしまいます。この宣言は必要ないのですか?教えてください。 import UIKit import AssetsLibrary class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate { var library = ALAssetsLibrary() var assets = NSMutableArray() override func viewDidLoad() { super.viewDidLoad() library.enumerateGroupsWithTypes( ALAssetsGroupType(ALAssetsGroupSavedPhotos), usingBlock: { (group: ALAssetsGroup!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in if group != nil { group.setAssetsFilter(ALAssetsFilter.allPhotos()) group.enumerateAssetsUsingBlock({ (asset: ALAsset!, index: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in if asset != nil { self.assets.addObject(asset!) print(asset) self.collectionView!.reloadData() } else {} }) } }, failureBlock: { (myerror: NSError!) -> Void in print("error occurred: \(myerror.localizedDescription)") } ) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { //return imageArray.count return self.assets.count; } func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { var cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)as! UICollectionViewCell // Configure the cell let assetImg :ALAsset = self.assets[indexPath.item] as! ALAsset; //print(assetImg) (cell.viewWithTag(1) as! UIImageView).image = UIImage(CGImage: assetImg.thumbnail().takeUnretainedValue()) return cell } }

その他の回答 (2)

回答No.3

No.2補足の質問について回答します。 > collectionView!.delegate = self > collectionView!.dataSource = self がなくても動いているのは、その替わりに storyboardを使ってdelegateとdataSourceを ViewControllerに接続しているのだと思います。 例えば、 http://www.dcom-web.co.jp/technology/swift3/ のtableViewの使い方の説明では、storyboardを使って delegateとdataSourceを接続する方法が説明されています。 どちらの方法を使ってもよいですが、どちらかの方法で delegateとdataSourceを設定しない限りコレクションビューは 動作できません。 > IBOutlet weak var collectionView:UICollectionView は、 self.collectionView!.reloadData() のように、制御(reloadData等)したいコレクションビューを 指定するのに必要です。 そういう制御をする必要がなく、デフォルトの動作に任せて表示できれば いいだけなら定義する必要はありません。 また、delegateで呼び出されるメソッドは、そのパラメータで collectionViewが渡されるものがあるので、これらのメソッド処理の中で コレクションビューを制御したい場合はcollectionViewパラメータを 使えばよいので、collectionViewプロパティとそのアウトレット接続は 不要です。 今回は、AssetsLibraryの処理の延長でreloadDataを実施したかったので その場合は、collectionViewプロパティを定義し、それを使う必要が あります。

dkong
質問者

お礼

いくつもの質問に対する丁寧な回答ありがとうございました。とても参考になりました。

回答No.2

No.2の補足の質問について回答します。 > @IBOutlet weak var collection:UICollectionView!としてみたら、エラーが消えたのですが、アプリが落ちてしまいます。この宣言は必要ないのですか?教えてください。 self.collectionView!.reloadData() を実行するために必要です。 が、「collection」ではなく「collectionView」です。 (どっちでもいいですが、reloadDataを実行しているコードと合わせる必要があります) たぶん、これを追加してエラーが消えたということは、 実際には「collectionView」を指定しているのだと思います。 が、実行して落ちたということは、たぶんこれをどこかの サイトからコピペして書いただけでアウトレット接続してないか、 接続したつもりだけど誤った接続になっているのだと思います。 その接続作業は、storyboardに貼りつけたラベルやボタンを コードから操作したい時にいつも実施する作業で、たぶんよく知っている 作業だと思うのですが、もしなんのことかわからなれば、 http://www.atmarkit.co.jp/ait/articles/1501/20/news023.html とかを参考にしてください。 もし誤って一度「collection」という名前で接続したことがあり、 その後それを「collectionView」に訂正したのであれば、 コード上の「collection」を「collectionView」に修正するだけでなく、 storyboardから再接続する作業が必要です。 そうしないと、storyboardは古い「collection」に接続していると 認識したままなのでやはり落ちます。 正しく接続されていれば、コードの左端の接続ポイントを示す ○記号が塗りつぶされていますが、接続されていない場合は 白抜きの○記号になります。 グループの取得処理やreloadData()を追加している場所は正しいので、 もうあとこれだけだと思います。

dkong
質問者

お礼

回答ありがとうがざいます。アウトレット接続しなおし、 collectionView!.delegate = self collectionView!.dataSource = self を加えたら、うまくいきました。ありがとうございます。 今回教えていただいたことや調べたことから疑問があります。追加コメントに質問させてください。

dkong
質問者

補足

いくつかのサンプルを見ていく中で、オブジェクトライブラリからstoryboardにUICollectionViewをドラッグ&ドロップして作っていく場合に、 @ IBOutlet weak var collectionView:UICollectionView?のアウトレット接続や collectionView!.delegate = self collectionView!.dataSource = self などの記述がなくてもUICollectionViewがきちんと表示されるものがありました。今回の自分にはこれから必要だったのですが、違いはなんなんでしょうか?よろしくお願いします。

関連するQ&A