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

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

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

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

1193閲覧

大量のCGImageを配列に格納する際のメモリ不足

sgt.kowalski

総合スコア34

Swift

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2017/08/19 11:23

教えてください!

UIImage を描画し、それを 360pixel×360pixel の CGImage に変換した上で、配列に格納するために、以下のようなコードを書いています。

配列に格納する枚数が数百枚単位になるので、シミュレータで見ると、メモリの使用量が3Gを超えます。

実機でテストすると、メモリ不足でアプリが落ちます。
これを回避する方法はあるのでしょうか?

for i in 0...bridgeArray.count - 1{ //bridgeArray[i]が空だったら、imageArrayForGifには現状の画像を加え、空じゃなかったら、DrawDataをbridgeArray[i]に入ってる個数分読んで描画し、imageArrayForGifに加える if bridgeArray[i].isEmpty == true{ imageView.image = canvasForGifInView canvasInImageArrayForGif = resizeUIImage(canvasForGifInView,scale) let canvasForGifCGImage = canvasInImageArrayForGif.cgImage imageArrayForGif.append(canvasForGifCGImage!) }else{ strokeDataForGif = bridgeArray[i] for k in 0...bridgeArray[i].count - 1{ drawDataForGif = strokeDataForGif[k] midPoint1 = convertPointInImageToPointInView(drawDataForGif.MidPoint1) midPoint2 = convertPointInImageToPointInView(drawDataForGif.MidPoint2) lastPoint = convertPointInImageToPointInView(drawDataForGif.LastPoint) canvasForGifInView = drawCurves(image: canvasForGifInView, fromPoint: midPoint1, toPoint: midPoint2, controlPoint: lastPoint) } imageView.image = canvasForGifInView canvasInImageArrayForGif = resizeUIImage(canvasForGifInView,scale) let canvasForGifCGImage = canvasInImageArrayForGif.cgImage imageArrayForGif.append(canvasForGifCGImage!) } }
//線の描画 func drawCurves(image:UIImage, fromPoint:CGPoint, toPoint:CGPoint, controlPoint:CGPoint) -> UIImage{ UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,true,0.0) image.draw(in: CGRect(x:0,y:0,width:imageView.bounds.width,height:imageView.bounds.height)) let context = UIGraphicsGetCurrentContext() context?.move(to:CGPoint(x:fromPoint.x,y:fromPoint.y)) context?.addQuadCurve(to:CGPoint(x:toPoint.x,y:toPoint.y),control:CGPoint(x:controlPoint.x,y:controlPoint.y)) context?.setBlendMode(CGBlendMode.normal) context?.setLineCap(CGLineCap.round) context?.setLineWidth(2 * scaleOfImageView) context?.setStrokeColor(UIColor(red:1.0,green:1.0,blue:1.0,alpha:1).cgColor) context?.strokePath() let drewImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return drewImage! }

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

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

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

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

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

Stripe

2017/08/19 12:59

アニメーションGIFでも作ろうとしているんですか?
Stripe

2017/08/19 13:48

360pixel×360pixelとなっていますが、Retinaディスプレイで実解像度が720pixel×720pixelってことになるんですか?
sgt.kowalski

2017/08/19 13:51

retina が 2 なのか 3 なのかっていう scale も取得してリサイズしているので、360pixel × 360pixelです。
Stripe

2017/08/19 14:02

つまり、resizeUIImage()のscale引数がそのままUIGraphicsBeginImageContextWithOptions()のscale引数にはなっていない、ということですね?
sgt.kowalski

2017/08/19 14:19

んーと、resizeUIImage()では、UIImage を 360/scale の大きさにして、それを CGImage に変換しています。
YokemuraTakeshi

2017/08/21 04:08

速度が求められる処理ですか?もしそれほどでもなければメモリでなくストレージを利用する手もあるかと思いますが。
sgt.kowalski

2017/08/21 16:51

速度はそんなに求めてないです!ストレージを利用するにはどうすればいいのでしょうか??
guest

回答1

0

自己解決

autoreleasepoolを使うことで解決しました。

上記質問ではgifを書き出すコードになっていますが、現在はmp4を書き出すようにしています。
配列に保存するのではなく、フレームごとに都度UIImageを書き出して、それをCGImageに変換し、生成中のmp4ファイルに継ぎ足していくという処理になっています。

それでも、メモリが不足してアプリがクラッシュする状況は同じだったのですが、そのUIImageCGImageautoreleasepool{}で囲ってやることでメモリが適宜解放されるようになり、使用メモリは最大時でも 100MB 強程度に収まるようになりました。

投稿2017/11/22 07:46

編集2017/11/22 07:50
sgt.kowalski

総合スコア34

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問