Slide 1

Slide 1 text

© RAKUS Co., Ltd. 1 メモリ最適化を究める! iOSアプリ開発における5つの重要なポイント Yuta.Hirakawa

Slide 2

Slide 2 text

2 ⾃⼰紹介 名前: Yuta Hirakawa 所属: 株式会社ラクス 担当: iOSアプリ開発 趣味: 料理、読書 @hirasan333

Slide 3

Slide 3 text

3 メモリ最適化を究める! iOSアプリ開発における5つの重要なポイント

Slide 4

Slide 4 text

4 循環参照によるメモリリーク キャッシュ

Slide 5

Slide 5 text

5 循環参照によるメモリリークについて iOSは利⽤されなくなったオブジェクトを メモリから開放してくれる仕組みがある。 ただし実装⽅法によっては「循環参照」が発⽣し、 メモリに残り続ける事象のことをメモリリークと⾔う。

Slide 6

Slide 6 text

6 循環参照によるメモリリークについて Object A (参照カウント1) Object B (参照カウント1) 互いに強参照

Slide 7

Slide 7 text

7 selfが強参照になりメモリリークが発⽣する。 AVCaptureDevice.requestAccess(for: .video) { granted in if granted { self.isCameraAuthorized = true } } 1.クロージャ内self参照による循環参照

Slide 8

Slide 8 text

8 解決⽅法:  [weak self]を追加し弱参照にする。 AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in if granted { self?.isCameraAuthorized = true } } 1.クロージャ内self参照による循環参照

Slide 9

Slide 9 text

class Child { var parent: Parent init(parent: Parent) { self.parent = parent } } 9 ⼦クラスに親クラスを持たせる必要がある場合、循環参照が発⽣する。 2.親⼦クラスの循環参照

Slide 10

Slide 10 text

10 解決⽅法:  ⼦クラスが持っている親クラスにweakを付けて弱参照にする。 class Child { weak var parent: Parent? init(parent: Parent) { self.parent = parent } } 2.親⼦クラスの循環参照

Slide 11

Slide 11 text

11 3.URLSessionConfiguration = .defaultの指定 プロポーザルに⼊れておりましたが、 後々調べた所問題無い判明しました。

Slide 12

Slide 12 text

12 3.URLSessionConfiguration = .defaultの指定 プロポーザルに⼊れておりましたが、 後々調べた所問題無い判明しました。 実は5つのポイントではなく4つのポイントでした。

Slide 13

Slide 13 text

class URLSessionClient { init(...) { super.init() self.session = URLSession(configuration: config, delegate: self, delegateQueue: queue) } } 13 URLSessionのdelegateがselfの状態にする。 4.URLSessionDelegateのextension実装

Slide 14

Slide 14 text

14 URLSessionDelegateをextensionで実装し、URLSessionClientの関数を 呼び出すと強参照になる。 extension URLSessionClient: URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { myMethod(didReceive: challenge, completion: completionHandler) } } 4.URLSessionDelegateのextension実装

Slide 15

Slide 15 text

15 解決⽅法:  SessionDelegate クラスを作成してデリゲート処理を分離し、  sessionClientプロパティをweakにする。 class SessionDelegate: NSObject, URLSessionDelegate { weak var sessionClient: URLSessionClient? func urlSession( _ session: URLSession, didReceive challenge: URLAuthenticationChallenge, ... ) { sessionClient?.myMethod(didReceive: challenge, completionHandler: completionHandler) } 4.URLSessionDelegateのextension実装

Slide 16

Slide 16 text

16 解決⽅法:  URLSessionClientではSessionDelegateに⾃⾝を設定する。 class URLSessionClient { private let delegate = SessionDelegate() init(...) { super.init() self.delegate.sessionClient = self self.session = URLSession(configuration: config, delegate: self.delegate, delegateQueue: queue) } } 4.URLSessionDelegateのextension実装

Slide 17

Slide 17 text

17 1度のみの利⽤であってもこのAPI利⽤して画像を取得すると メモリ上にキャッシュされる。 UIImage(named: "imageName") Image("imageName") 5.UIImage(named:)による画像呼び出し

Slide 18

Slide 18 text

18 解決⽅法:  再利⽤しない画像はcontentsOfで読み込む。 if let path = Bundle.main.path(forResource: "imageName", ofType: "png"), let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let image = UIImage(data: data) { Image(uiImage: image) } 5.UIImage(named:)による画像呼び出し

Slide 19

Slide 19 text

19 ● 循環参照(強参照)に気をつける。 ○ クロージャ ○ 親⼦関係にあるクラス ○ extension ● UIImageやImageで画像を取得する場合はキャッシュされることを 意識する。 メモリ最適化を究める! iOSアプリ開発における5つの重要なポイント Yuta Hirakawa @hirasan333