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

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

新規登録して質問してみよう
ただいま回答率
85.51%
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

解決済

1回答

3724閲覧

UICollectionViewを使ったカメラロールの表示 スクロールでmemory warningが起きる

gami

総合スコア17

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/07/25 05:16

編集2016/07/26 07:07

###前提・実現したいこと
[iOS swift]UICollectionView、PHAssetを使ったカメラロールの表示
セルにカメラロールの画像を入れこむことは下記のコードで実現できたのですが、メモリの解放がうまくできません。

###発生している問題・エラーメッセージ
画像が1000枚程度カメラロールにあり、初期表示は問題ないが素早くスクロールをするとアプリケーションが落ちてしまします。
正しい表示の方法、メモリの解放等ご教授いただけたらと思います。
よろしくお願いします。

Received memory warning.

###該当のソースコード

swift

1import UIKit 2import Photos 3 4class albumViewController2: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate { 5 6 var photoAssets = [PHAsset]() 7 var photoImages = [UIImage?]() 8 var photoCounts:Int = 0 9 var collectionView:UICollectionView! 10 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 let screenWidth = CGFloat( UIScreen.mainScreen().bounds.size.width) 14 15 self.view.backgroundColor = UIColor.grayColor() 16 17 //カメラロールから画像取得 18 getAllPhotosInfo() 19 20 //レイアウト部 21 let flowLayout = UICollectionViewFlowLayout() 22 flowLayout.scrollDirection = .Vertical 23 flowLayout.minimumInteritemSpacing = 0.0 24 flowLayout.minimumLineSpacing = 0.0 25 flowLayout.itemSize = CGSizeMake(screenWidth / 4, screenWidth / 4) 26 27 // コレクションビュー作成 28 collectionView = UICollectionView(frame: view.frame, collectionViewLayout: flowLayout) 29 collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell") 30 collectionView.dataSource = self 31 collectionView!.delegate = self 32 collectionView.backgroundColor = UIColor.clearColor() 33 view.addSubview(collectionView) 34 } 35 36 override func didReceiveMemoryWarning() { 37 super.didReceiveMemoryWarning() 38 } 39 40 41 func getAllPhotosInfo() { 42 photoAssets = [] 43 44 // ソート条件を指定 45 let options = PHFetchOptions() 46 options.sortDescriptors = [ 47 NSSortDescriptor(key: "creationDate", ascending: false) 48 ] 49 50 // 画像すべてのAssetを取得 51 let assets: PHFetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: options) 52 assets.enumerateObjectsUsingBlock { (asset, index, stop) -> Void in 53 self.photoAssets.append(asset as! PHAsset) 54 } 55 photoCounts = photoAssets.count 56 } 57 58 59 //コレクションビュー 60 func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 61 return 1 62 } 63 64 func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 65 return photoCounts 66 } 67 68 func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 69 let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as UICollectionViewCell 70 71 cell.backgroundColor = UIColor.brownColor() 72 //PHAseetから画像取得のリクエストを投げてcellにセット 73 let asset = photoAssets[indexPath.row] 74 var photo: UIImage? 75 let manager: PHImageManager = PHImageManager() 76 77 78 for subview in cell.contentView.subviews{ 79 subview.removeFromSuperview() 80 } 81 manager.requestImageForAsset(asset, 82 targetSize: CGSizeMake(CGFloat(asset.pixelWidth) , CGFloat(asset.pixelHeight) ), 83 contentMode: .AspectFill, 84 options: nil) { (image, info) -> Void in 85 photo = image! 86 } 87 88 let imageview:UIImageView=UIImageView(frame: CGRectMake(1, 1, (self.view.bounds.width / 4) - 2, (self.view.bounds.width / 4) - 2 )) 89 imageview.image = photo 90 imageview.contentMode = .Center 91 imageview.clipsToBounds = true 92 cell.contentView.addSubview(imageview) 93 94 return cell 95 96 } 97}

###補足情報
Xcode 7.2.1 swift

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

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

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

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

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

fuzzball

2016/07/25 07:51

ゆっくりスクロールさせると落ちないんでしょうか?
gami

2016/07/25 07:59

閲覧ありがとうございます。 ゆっくりスクロールさせると落ちません。一画面に28セル表示させていて、勢い良くスクロールさせるとカクついてmemory warningが起きます。
fuzzball

2016/07/25 08:07

画像リクエストの処理を無くしても同じようになるでしょうか?具体的には、「//PHAseetから画像取得の〜」から「photo = image! }」までコメントアウト。「imageview.image = photo」もコメントアウト。
gami

2016/07/26 00:37

ご指摘のように画像リクエストをコメントアウトしたところ症状は出ませんでした。
guest

回答1

0

ベストアンサー

書き逃げしておきます。

requestImageForAsset()を放置しているのが原因じゃないかなぁと思っています。

Subviewに関しては、removeFromSuperviewでひっぺがして処分していますので、それと同じようにrequestImageForAsset()も処分してやって下さい。リクエストしたときにrequestIDを保存しておいて、cancelImageRequest(requestID)してやればいいと思います。

他の原因、もしくは、他にも原因があるかも知れませんが。

ただのメモリ不足?

大きな画像を大量に読み込んでメモリ不足になっているのではないか?という推測。
小さいサイズでリクエストするようにします。(requestID関係は一旦削除していいかも)

swift

1override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 2 : 3 //imageviewにはcellのサイズを渡す 4 let imageview:UIImageView = UIImageView(frame: CGRectMake(1, 1, CGRectGetWidth(cell.frame)-2, CGRectGetHeight(cell.frame)-2)) 5 //imageview.image = photo //ここでは設定しない 6 imageview.contentMode = .ScaleAspectFit //お好みで 7 imageview.clipsToBounds = true 8 cell.contentView.addSubview(imageview) 9 10 //リクエスト 11 manager.requestImageForAsset( 12 asset, 13 targetSize: imageview.frame.size, //imageviewのサイズでリクエスト 14 contentMode: .AspectFit, //imageviewに合わせる? 15 options: nil 16 ) { (image, info) -> Void in 17 //imageviewにセット 18 imageview.image = image //読み込んだ画像をセット 19 let degraded = (info![PHImageResultIsDegradedKey]?.boolValue)! 20 //print(image!.size, degraded) 21 if degraded { 22 //print(indexPath, "continue...") 23 } 24 else 25 { 26 //print(indexPath, "done") 27 } 28 } 29 30 return cell 31}

投稿2016/07/25 09:20

編集2016/07/26 05:33
fuzzball

総合スコア16731

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

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

gami

2016/07/26 01:29

ご回答ありがとうございます。 下記コードでcancelImageRequestを試したのですが、症状が変わりませんでした。 呼び出し方、呼び出すタイミングが悪いのでしょうか func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as UICollectionViewCell cell.backgroundColor = UIColor.brownColor() //PHAseetから画像取得のリクエストを投げてcellにセット let asset = photoAssets[indexPath.row] var photo: UIImage? let manager: PHImageManager = PHImageManager() var imageRequests = [NSIndexPath: PHImageRequestID]() for subview in cell.contentView.subviews{ subview.removeFromSuperview() } if let request = imageRequests[indexPath]{ manager.cancelImageRequest(request) } manager.requestImageForAsset(asset, targetSize: CGSizeMake(CGFloat(asset.pixelWidth) , CGFloat(asset.pixelHeight) ), contentMode: .AspectFill, options: nil) { (image, info) -> Void in photo = image! } let imageview:UIImageView=UIImageView(frame: CGRectMake(1, 1, (self.view.bounds.width / 4) - 2, (self.view.bounds.width / 4) - 2 )) imageview.image = photo imageview.contentMode = .Center imageview.clipsToBounds = true cell.contentView.addSubview(imageview) return cell }
fuzzball

2016/07/26 01:47

var imageRequests = [NSIndexPath: PHImageRequestID]() これ、関数の中に書いちゃダメだと思いますが。
gami

2016/07/26 02:19

すみません不識でした。「該当のソースコード」に追記いたしました。症状は解決しませんでした。
fuzzball

2016/07/26 05:31 編集

imageRequests[]にrequestIDが保存されていません。 ただ、この件は関係ないような気がしてきました。
fuzzball

2016/07/26 05:32

requestIDのことは忘れて別方面から攻めてみました。 回答に追記しています。
gami

2016/07/26 05:34

すみません。再度修正いたしました。引き続き原因を探っていきます。
fuzzball

2016/07/26 06:19

requestIDを保存する場合は、photoAssetsなどと同じように配列に保存しないといけません。複数のリクエストが同時に進行しますので。
gami

2016/07/26 07:14

なるほど 非同期でリクエストされると同時に配列にリクエストIDを追加していき、リクエストが消えないようなら消すということですね。 追記回答を参考に書き直した所、memory warningはなくなりました。ありがとうございます。しかしながら、requestImageForAssetをしてからimageviewにimageをセットしていますが、非同期ゆえにか画像がセットされないセルが多々見受けられるようになりました。 別の問題になりますが、ここにコードを記します。 ```swift func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as UICollectionViewCell let asset = photoAssets[indexPath.row] let manager: PHImageManager = PHImageManager() let imageview:UIImageView=UIImageView(frame: CGRectMake(1, 1, CGRectGetWidth(cell.frame)-2, CGRectGetHeight(cell.frame)-2)) for subview in cell.contentView.subviews{ subview.removeFromSuperview() } cell.backgroundColor = UIColor.brownColor() imageview.contentMode = .ScaleAspectFill imageview.clipsToBounds = true cell.contentView.addSubview(imageview) //画像取得リクエスト manager.requestImageForAsset(asset, targetSize: imageview.frame.size, contentMode: .AspectFill, options: nil) { (image, info) -> Void in imageview.image = image } return cell } ```
fuzzball

2016/07/26 07:24

コードはここに書かないで下さい。 あと、質問内容が変わるのであれば新規に質問して下さい。
gami

2016/07/26 07:47

承知しました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問