web-dev-qa-db-ja.com

呼び出されないDeinit

ViewControllerオブジェクトを作成して、Navigation Controllerにプッシュしています。オブジェクトがスタックからポップされている場合-オブジェクトはリリースされておらず、Deinitは呼び出されていません。その理由は何ですか?

プッシュするコードは次のとおりです。

self.navigationController?.pushViewController(CustomViewController(), animated: true)

そして、ここにポップするコードがあります:

 self.navigationController?.popViewControllerAnimated(true)
46
YogevSitton

同様の問題がありました。空のdeinitメソッドをクラスに追加し、ブレークポイントを追加しました。

deinit {

}

その結果、呼び出されることはありません。
本文にコードを追加するとすぐに、期待どおりに機能し始めました。

deinit {
    print("deinit called")
}

したがって、deinitメソッドが空でないことを確認してください。
PS。私はSwift 2、Xcode 7.1を使用しています

63
Vlad Papko

クラスまたはクラスに含まれるプロパティは、ポップしたView Controllerへの参照を作成しますか?

UIViewControllerがオブジェクトのインスタンスを作成し、そのView Controllerへの「強い」参照(明示的に「weak」または「unowned」と明示的に宣言されていない参照)を作成し、View Controllerがそのオブジェクトも同様に、どちらも割り当て解除されません。これは強力な参照サイクルと呼ばれ、ここに文書化されています(深刻なSwift開発者)には必ずお読みください):

Swiftプログラミング言語(Swift 3.0.1):自動参照カウント

クロージャーは、トラブルに巻き込まれる可能性のある、よりinなケースです。

実験として試してみることの1つは、コントローラーをプッシュしてポップすることですbeforeviewDidLoadまたは初期化で何かを行い、deinitメソッドがと呼ばれています。もしそうなら、あなたはあなたが見ている症状につながるあなたがしていることを少しずつ発見できるはずです。

(他の回答が指摘しているように)診断を妨げることができるもう1つのことは、私が難しい方法を学んだことですが、deinitメソッドに実行可能なステートメントが含まれていない場合、deinit()に対してデバッガーブレークポイントが取得されないことです空の場合はdeinit呼び出しを最適化します。したがって、少なくともdeinit()が呼び出されていることを確認する場合は、そこにprintステートメントを配置します。

47
clearlight

私はこのチュートリアルを使用していました Custom TabBar 指定されたページでカスタムシーケンスを使用しました。メモリの問題は、親ビューコントローラーへの強い参照を持つサブビューが原因でした。

class WBMNewsFeedV: UIView
{
   var parentVC:WBMHomeTabVC!
}

WBMNewsFeedV-サブクラス

parentVC:WBMHomeTabVC-親クラスViewController

私はそれを次のように変更しました:

class WBMNewsFeedV: UIView
{
    weak var parentVC:WBMHomeTabVC!
}

そのため、強参照はサブビュー内にネストされ、最初は表示されませんでした。これが誰にも役立つことを願っています。変更後、deinitは常に呼び出されました

WBMHomeTabVC

16
MB_iOSDeveloper

NotificationCenterが、表示されているビューへの強い参照を保持しているときに同じ問題が発生したため、リリースされませんでした。そのため、ブロックに[weak self]を追加する必要がありました。

(viewDidLoad内)

NotificationCenter.default.addObserver(forName: .showFoo, object: nil, 
  queue: OperationQueue.main) { [weak self] (notification) in
    if let foo = notification.userInfo?["foo"] as? Foo {
            self?.afooButton!.setImage(UIImage(named: "foo"), for: .normal)
    }
}
10
David Hernandez

View Controllerにタイマーがあり、ラベルを更新するために毎分実行されていました。 deinitでタイマーを無効にするための呼び出しを行いました。これは、Objective-C(deallocで)で常に行ったことであり、機能していると確信しています。しかし、Swiftでは少し異なるようです。そのため、時間の作成/無効化コードをviewWillAppear/viewWillDisappearに移動しました(これはより理にかなっています)。

7
CMash

同様の問題が発生しました。私の問題は、デリゲートの割り当てがクラス型プロトコルで「弱い」として指定されていないコントロールへの強い参照が原因で発生したようです。

6
nwales

ininitの行コードを追加します。空のdeinitにブレークポイントを置いた場合、コンパイラはそこにあなたを止めません:

deinit {
print("any thing")
}

それが動作します ;)

6
Devesh

私が見つけたのと同じ問題がありましたが、他のクラスデリゲートの弱い参照をしていません

protocol SomeClassDelegate : AnyObject {
    func someClassDelegateMethod(<param>)
}

class SomeClass: NSObject {

    // Make delegate weak reference 
    weak var delegate:InfractionDataManagerDelegate? = nil
    < some code >
}

現在、実装クラスでdeinitが呼び出されています。

2
mrunal thanki

私は同じ問題に直面しました。私の場合、UIView.animateWithDuration ...の終わりのないサイクルは、ViewControllerをメモリに保持し、deinitの呼び出しをブロックします。このようなものを使用する場合は、ViewControllerを削除する前にまず停止する必要があります。お役に立てば幸いです。

2
Joe

検出するのが非常に難しいとわかったEdgeケースを追加するだけです。

UnsafeMutablePointersを割り当て、View Controller内でポインティとしてself(UIViewController)を提供する場合は、必ずpointer.deinitialize(count:)not just pointer.deallocate()

そうしないと、selfへの参照が残り、UIViewControllerは初期化解除されません。

2

同様の問題がありました: scrollview に含まれる arranged subviews of a * stackview "にUIViewsがありました詳細ビューコントローラー: stackview から戻るボタンタップ(willMove(toParent parent: UIViewController?))からUIViewsを削除したときに機能しました。あなたのView Controllerには次のようなものがあります:let session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())selfは、 Back をクリックしたときに詳細なView Controllerの割り当てを解除できない場合があります。マスターに移動)

1
3000

まず最初にdeinitを定義してください

deinit {
    print("OverlayView deinit")
}

Xcodeのオブジェクトグラフを使用して、作成されているインスタンスの数を確認し、割り当てが解除されていない場合は成長し続けます。 ファイルの上に別のViewControllerのプロパティを作成していたので、それを移動し、問題を解決した使用中のスコープに配置しました。そして、そのdeinitが呼び出しを開始しました。

さらに、私はuiviewプロパティを使用して、いくつかの場所でViewControllerからアクセスする必要があるオーバーレイを表示しました。それをオプションにし、removefromsuperviewを呼び出した後にnilに設定しました。

var overlay: OverlayView?
overlay = nil

それでも呼び出しが解除されていない場合、上記のように保持サイクルの問題が発生する可能性があり、その場合、このcontroller(A)をコールバックして別のviewcontroller(B)をチェックし、そのうちの1つを弱い変数として設定する必要があります。

0
Ammar Mujeeb