LoginSignup
5
4

More than 5 years have passed since last update.

リーク解消のsampleをここにちょこまか書いていく。

Last updated at Posted at 2017-10-14

メモリリークを解消した時など少しずつsampleを書いて行こうという感じのものです。
ちなみに、書いている本人としてリークがあるコードを否定したい訳ではないです(。・ω・。)
大量になればなるほどや、色々な原因でリークは発生するし、リークでもこれは別にいいんじゃないのとかもあると思うので、ただ、もしこのリーク無くしたらみたいなことがある時の参考になれば嬉しいと書いています。
ちなみに、判断はxcodeのinstrumentsでの判断結果です。
ちなみにinstrumentsでのチェックは直したコードを一回ビルドしてからあの赤いポチョを押さないと前の残っていたものでチェックされてしまいます。

リーク発生code

AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    weak var nc: UINavigationController?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        nc = UINavigationController(rootViewController: firstViewController())
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.rootViewController = nc
        return true
    }

リーク解消code

AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    weak var nc: UINavigationController?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        nc = UINavigationController(rootViewController: firstViewController())

        self.window?.rootViewController = nc 
        return true
    }

:shamrock:補足:windowをインスタンス化したことによりこれが残ってしまいメモリリークとなっていたっぽい?

リーク発生code

ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()

       sampleImageView.frame = self.view.frame

        let imgURL = URL(string: "https://www.???.jpg")!
        let session = URLSession(configuration: .default)
        let download = session.dataTask(with: imgURL) { (data, response, error) in
            if (response as? HTTPURLResponse) != nil{
                if let imageData = data {
                    DispatchQueue.main.async {
                        let imageimage = UIImage(data: imageData)
                        self.sampleImageView.image = imageimage
                    }
                }
            }
        }
        download.resume()

        self.view.addSubview(self.sampleImageView)

リーク解消code

ViewController.swift
    var sampleImageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()

       sampleImageView.frame = self.view.frame

        let imgURL = URL(string: "https://www.???.jpg")!
        let session = URLSession(configuration: .default)
        let download = session.dataTask(with: imgURL) { (data, response, error) in
            if (response as? HTTPURLResponse) != nil{
                if let imageData = data {
                    DispatchQueue.main.async {
                        let imageimage = UIImage(data: imageData)
                        self.sampleImageView.image = imageimage
                    }
                }
            }
        }
        session.invalidateAndCancel()
        download.resume()

        self.view.addSubview(self.sampleImageView)

:shamrock:補足:session.invalidateAndCancel()があるかないかなのですが、場所はここが適切かはちょっとわかっていないです。

リーク発生(画面を閉じる際にdeinitが呼ばれない。 XcodeのInstrumentsでもリークが発生)
動作としては以下のようなもの(モーダルで遷移、Button押した時にはログが出ます。)
samplemove.gif

ViewController.swift
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }
    @IBAction func gosampleViewController(_ sender: UIButton) {
        self.present(sampleViewController(), animated: true, completion: nil)
    }
}
sampleViewController.swift
import UIKit

class sampleViewController: UIViewController {

    var sample:sampleclass!

    override func viewDidLoad() {
        super.viewDidLoad()

        sample = sampleclass()

        sample.action = {
            self.log()
        }
    }

    deinit {
        print("sampleViewController deinit")
    }

    func log(){
        print("ボタンが押されました。")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func tap(_ sender: Any) {
        sample.action!()
    }

    @IBAction func back(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }
}

sampleclass.swift
import UIKit

class sampleclass: NSObject {
    var action:(()->())?
}

リーク解消

ViewController.swift
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }
    @IBAction func gosampleViewController(_ sender: UIButton) {
        self.present(sampleViewController(), animated: true, completion: nil)
    }
}
sampleViewController.swift
import UIKit

class sampleViewController: UIViewController, sampleprotocol{

    var sample:sampleclass!

    override func viewDidLoad() {
        super.viewDidLoad()

        sample = sampleclass()
        sample.delegate = self
    }

    deinit {
        print("sampleViewController deinit")
    }

    func log(){
        print("ボタンが押されました。")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func tap(_ sender: Any) {
        sample.delegate?.action()
    }

    @IBAction func back(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }

    //sampledelegate
    func action() {
        self.log()
    }

}

sampleclass.swift
import UIKit

protocol  sampleprotocol:class{
    func action()
}

class sampleclass: NSObject {
    weak var delegate:sampleprotocol?
}

:shamrock:補足:

sample.action = {
            self.log()
        }

の部分がリークの原因でした。

:shamrock:コードまだ書いていないけどこう言う時あるよ的なもの以下
・protocole使っている時!使う型がわからないとなるので,以下のようにclassですよを指定していないとほぼリーくする気がしています。ちなみに宣言する時はvar でなく weak var にしないとリークします。


protocol sample:class{
    func a()
}

参考:Swift で Class-Only Protocol を定義する

5
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4