web-dev-qa-db-ja.com

ViewController respondsToSelector:割り当て解除されたインスタンスに送信されるメッセージ(CRASH)

わかりました、ここに取り引きがあります、私はhate私のデバッグおよびクラッシュについての質問を出します。私は通常自分でそれらを処理しますが、できないすでに複数の質問を見ているの後でも、これを回避するためです。

わかりましたので、ここに問題があります。このスタックトレースで、アプリがランダムにオンとオフにクラッシュします。

*** -[ViewController respondsToSelector:]: message sent to deallocated instance 0x1e5d2ef0

ViewControllerは変化する可能性があり、コードがクラッシュする場合があります[〜#〜] no [〜#〜]特定のViewControllerに関連して所有または呼び出します。

また、そのコンソールトレースを取得するために、ゾンビを有効にしました。そうしないと、コンソールプリントがまったく表示されず、objc_msgSendは、リリースされたものにメッセージを送信していることを意味します。しかし、私はそれがどこにあるか見つけることができません...私は本当に立ち往生しています!通常、私はalwaysクラッシュをデバッグするので、本当にこれにこだわっています。

繰り返しますが、これはさまざまな場所で、さまざまな時間に、オンとオフでクラッシュします。そして、それがクラッシュする場所は、ほとんどnoViewControllerに関連しています。そして、これは非常に紛らわしいと思います。

私のコードが必要ですか? たくさんのファイルがあり、さまざまな場所でクラッシュしているため、コードの配布は面倒です!

幸運にもシンボリックブレークポイントを追加しようとしましたが、iOS用のInstrumentsアプリケーションではZombiesを使用できません。サポートされないアーキテクチャフレームワークがあるため、シミュレータでアプリを実行できません。

みんな、ありがとう...

95
MCKapur

Instrumentsを使用して、割り当て解除されたインスタンスエラーを追跡します。アプリケーションのプロファイル(Cmd ⌘+I)およびZombies templateを選択します。アプリケーションの実行後、クラッシュを試みます。そのようなものを取得する必要があります。

enter image description here

ポップオーバーのアドレスの横にある矢印をクリックして、割り当てが解除された後に呼び出されたオブジェクトを表示します。

enter image description here

変更されたすべての呼び出しで、このオブジェクトのカウントが保持されるようになります。これは、直接保持/解放メッセージを送信したり、自動解放プールを空にしたり、NSArrayに挿入したりするためです。

RefCt列は、アクションが呼び出された後のretainCountを示し、Responsible Callerは、実行されたクラス名とメソッドを示します。保持/リリースをダブルクリックすると、インストゥルメントはこれが実行されたコード行を表示します(これが機能しない場合は、呼び出しを選択して、拡張詳細ペイン):

enter image description here

これにより、オブジェクトのすべてのretainCountライフサイクルを調べることができ、おそらくすぐに問題を見つけることができます。必要なことは、欠落しているretainを最新のreleaseで見つけることです。

169
Johnnywho

同様の問題がありました。私の場合、viewControllerはnavigationControllerイベントを取得する必要があったため、Navigation Controllerデリゲートとして登録していました。

 self.navigationController.delegate = self;

クラッシュは、そのコントローラーが割り当て解除されたが、View Controllerのデリゲートのままであったときに発生します。このコードをdeallocに追加しても効果はありません。

-(void) dealloc
{
    if (self.navigationController.delegate == self)
    {
        self.navigationController.delegate = nil;
    }

deallocが呼び出された時点で、View Controllerはビュー階層から既に削除されているため、self.navigationControllerはnilであるため、比較は必ず失敗します! :-(

解決策は、このコードを追加して、VCが実際にそうなる直前にビュー階層を離れるのを検出することでした。押されていない

-(void) viewWillDisappear:(BOOL) animated
{  
   [super viewWillDisappear:animated];
   if ([self isMovingFromParentViewController])
   {
      if (self.navigationController.delegate == self)
      {
           self.navigationController.delegate = nil;
      }
   }
}

これ以上クラッシュしません!

59

それを解決できない人のために、他のテクニックをいくつか紹介します。

https://stackoverflow.com/a/12264647/539149

https://stackoverflow.com/a/5698635/539149

https://stackoverflow.com/a/9359792/539149

https://stackoverflow.com/a/15270549/539149

https://stackoverflow.com/a/12098735/539149

Xpop 5でInstrumentsを実行するには、プロジェクトポップアップ->スキームの編集...プロファイル-> Instrumentを選択し、AllocationsまたはLeaksを選択します。

ただし、com.Apple.main-threadから直接送信されるメッセージの場合、おそらく何も表示されません

私は2時間以上これに頭を打ちましたが、答えは過剰なリリースであることが判明しました。

[viewController release];
viewController = NULL;

問題は、リリースが変数をNULLに設定しないことです

つまり、NULL呼び出しに設定すると再度解放され、refcountをデクリメントし、viewControllerを参照する変数が終了するまですぐにメモリを解放します。

そのため、ARCを有効にするか、プロジェクトでreleaseまたはNULLを使用し、両方を使用しないようにしてください。私の好みはNULLを使用することです。その場合、ゾンビを参照する可能性はありませんが、オブジェクトが解放された場所を見つけるのが難しくなります。

4
Zack Morris

昨日、iOSで同じ問題に遭遇しました。 Appの「About」サブビューでIAPを作成し、「About」viewDidLoadにTransaction Observerを追加しました。初めて購入したときは問題ありませんが、メインウィンドウに戻ってサブビューについて再度入力すると、「割り当て解除されたインスタンスに送信されたメッセージ」という問題が発生し、アプリがクラッシュしました。

- (void)viewDidLoad
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];                                           object:nil];
}

DeallocでTransaction Observerを削除すると、問題は解決します。

- (void)dealloc
{
    // Even though we are using ARC, we still need to manually stop observing any
    // NSNotificationCenter notifications.  Otherwise we could get "zombie" crashes when
    // NSNotificationCenter tries to notify us after our -dealloc finished.

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
4
Ouyang Yong

私は非常によく似た問題を抱えていましたが、それはNavigation Controllerのデリゲートセットによるものだとわかりました。

以下は私の問題を解決しました、

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (self.navigationController.delegate != self) {
        self.navigationController.delegate = self;
    }
}

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}
4
thatzprem

私は同じ問題を抱えていましたが、行またはコードのステートメントを示していないため、どのデリゲートの原因の問題を見つけるのは困難でした。

  1. Xibファイルを開き、ファイルの所有者から、「接続インスペクタを表示」右側のメニューを選択します。デリゲートが一覧表示され、疑わしいnilに設定します。
  2. (私の場合と同じ)Textfieldのようなプロパティオブジェクトは問題を作成できるため、デリゲートをnilに設定します。
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}
2
nadim

OS Xでも同じ問題がありました。

@SoftwareEvolvedがすでに述べたように、これを解決するには十分ではない- (void)deallocメソッド。ただし、残念ながら- (void)viewWillDisappearはバージョン10.10以降でのみ使用できます。

NSViewControllerサブクラスにカスタムメソッドを導入し、すべてのゾンビに危険な参照をnilに設定しました。私の場合、それはNSTableViewプロパティ(delegateおよびdataSource)でした。

- (void)shutdown
{
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
}

それで全部です。スーパービューからビューを削除しようとするたびに、このメソッドを呼び出す必要があります。

2
Astoria