iOSのカメラアプリ制作時にメモリーリークで困った…

エンジニアのgabachoと申します。
この度はiOSのカメラアプリを制作していた際にメモリーリークでとても困ったのでシェアさせていただきます。

開発環境

  • Objective-C (古きを知り新しきをなんたらです)
  • Swift2.2 (古きを知りなんたらです)
  • Xcode7.3.1 (古きなんたらです)

一応Swift3.0に対応するコードも後述します。
4.0以降は元気があれば動くと思います(動くとは言っていない)

状況

1. UIImagePickerControllerでカメラ機能を実装
2. 撮影した画像を内部ストレージに保存
3. これらを数十回繰り返すとアプリが落ちる

開発環境がニッチなら状況もかなりニッチです
そのため4大奥義である複製保存を発動することもできず苦労しました

解決方法

結局どう解決したかというと、Cool-iOS-Cameraというカメラライブラリーを使いました。
とてもシンプルなカメラライブラリーかつ機能をかなり網羅していたのでこのライブラリーを選びました。
また、Objective-Cということもあり、Swiftのバージョンがいくつでも大丈夫というストライクゾーンの広さが大きな理由です。
(私もストライクゾーン広いのでいくつでも大丈夫です!)

実装方法

1. ライブラリーをプロジェクトに突っ込む

2. Bridging-Header.hに追加もしくは作成

#import "CameraSessionView.h"

3. ViewControllerでデリゲートを継承する

class OnkochishinViewController: CACameraSessionDelegate {

4. Viewでカメラを呼び出す

var onkochishinView = CameraSessionView()

// 「写真を撮る」とかのカメラを機能を立ち上げるアクション内
func onClickPhotoAction() {
    onkochishinView = CameraSessionView(frame: self.view.frame)
    onkochishinView.delegate = self
    self.view.addSubview(onkochishinView)
}

これでひとまずカメラ機能を呼び出すことができます。

5. 撮影された画像を受け取る
コード例です

// Swift3.0とかなら didCapture(_ image: UIImage!) です
func didCaptureImage(image: UIImage) {
    let uuid = NSUUID().UUIDString // Swift3.0とかなら uuidString です
    let imageName = "\(uuid).PNG"
    let jpgImageName = "\(uuid)-thumb.JPG"
    let data = UIImagePNGRepresentation(image)
    let jpgData = UIImageJPEGRepresentation(image, 0.7)
    let localPath = relationData.setFile(imageName, data: data!)
    let _ = relationData.setFile(jpgImageName, data: jpgData!)
    onkochishinModel.saveValuable(NSURL(fileURLWithPath: localPath))
    onkochishinView.removeFromSuperview()
}

こんな感じで動くと思います。

ただここで一つ問題が発生しました。
画面の向き変更にロックをかけている場合にカメラの向きを取得できず、横にしてとった写真も縦に表示されてしまう状態でした。
次から次へと…..フリーザ倒したと思ったらクウラがすぐ攻めてきた気分
ただしこいつも外部ライブラリーを使うことで解決しました。
外部ライブラリーがおらに元気を分けてくれた。(やっぱ元気があれば動く)

状況2

  • 外部カメラライブラリー使ったら画面ロックしてる状態でカメラの向きが取得できない

解決方法2

MotionOrientationを使って解決しました。
このライブラリーなら画面の向き変更にロックされていても向きを取得してくれます。

実装方法2

1. ライブラリーをプロジェクトに突っ込む

2. Bridging-Header.hに追加

#import "MotionOrientation.h"

3. ライブラリーを使って向きを取得する

var orientation: Int?
switch MotionOrientation.sharedInstance().deviceOrientation.rawValue {
//逆さ
case 2:
    orientation = 8

//左下
case 3:
    orientation = 1

//右下
case 4:
    orientation = 3

//通常
default:
    orientation = 6
}

これで地球が救われました。

間違いなどがありましたらすみません。
ご指摘いただけましたらありがたいです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です