2

私は何か間違ったことをしているに違いありませんが、自動参照カウントのドキュメントはそれが何であるかについてのヒントを私に与えません。私がやっていることは、デリゲートメソッド内からブロックコールバックを使用してメソッドを呼び出すことです。ブロック内から同じデリゲートにアクセスすると、アクセスが悪くなります。問題は、渡したオブジェクト(デリゲートにメッセージを送信しているloginController)が明らかに解放されないことです。ブロック内でアクセスしないと、問題なくメソッドを複数回呼び出すことができます。これが私のコードです:

- (void)loginViewDidSubmit:(MyLoginViewController *)loginController
{
    NSString *user = loginController.usernameLabel.text;
    NSString *pass = loginController.passwordLabel.text;

    __block MyLoginViewController *theController = loginController;
    [self loginUser:user withPassword:pass callback:^(NSString *errorMessage) {
        DLog(@"error: %@", errorMessage);
        DLog(@"View Controller: %@", theController);    // omit this: all good
        theController = nil;
    }];
}

NSZombieEnabledは何もログに記録せず、gdbからの使用可能なスタックトレースはありません。私はここで何が間違っているのですか?ポインタをありがとう!


編集:

問題の範囲が広いと思いました。上記のコールバックはNSURLConnectionDelegateメソッドから呼び出されます(ブロック自体はそのデリゲートの強力なプロパティであるため、ARCはBlock_copy()を呼び出す必要があります)。このシナリオでは、特別な測定を行う必要がありますか?

フロー(loginControllerは常に表示されたままです):

loginController

[delegate loginViewDidSubmit:self];

デリゲートを表示

(method shown above calls the loginUser: method, which does something like:)
httpDelegate.currentCallback = callback;
httpDelegate.currentConnection = // linebreak for readability
    [[NSURLConnection alloc] initWithRequest:req
                                    delegate:httpDelegate
                            startImmediately:YES];

NSURLConnectionDelegate

- (void)connection:(NSURLConnection *)aConnection
  didFailWithError:(NSError *)error
{
    if (NULL != currentCallback) {
        currentCallback([error localizedDescription]);
        self.currentCallback = NULL;
    }
}

そして、これは私が悪いアクセスを取得する場所ですが、そのloginController変数にアクセスする場合に限ります...

4

3 に答える 3

3

copy属性をプロパティに設定するか、ブロックに対して「copy」メソッドを呼び出すだけです。

- (void)loginUser:(NSString *)user withPassword:(NSString *)pass callback:(void (^callback)(NSString *))
{
    callback = [callback copy];
于 2011-09-14T23:21:20.240 に答える
1

実際の解決策は、ブロックを強力なプロパティとして持っていたということでしたが、それはコピープロパティである必要がありました。D'oh!


最初の「解決策」:

アクセス不良を防ぐ方法を見つけました。上記の編集で示したように、View DelegateはブロックをhttpDelegate(別のクラスのインスタンス)に転送し、httpDelegateはブロックへの強力な参照を保持します。ブロックを一時変数に割り当て、一時ブロック変数を転送すると、何らかの理由で問題が解決します。それで:

説明されているように、これはブロックの実行時にクラッシュします

httpDelegate.currentCallback = callback;

これは動作します

MyCallbackType aCallback = callback;
httpDelegate.currentCallback = aCallback;

私はこれを答えとして受け入れます。誰かがより多くの洞察を持っているなら、私は私の決定を修正してうれしいです。:)

于 2011-09-13T18:39:55.380 に答える
0

デリゲートを呼び出した直後にloginControllerが停止していることが何が起こっているのかわかります。したがって、クラッシュが発生します。これ以上の情報がなければ、考えられるシナリオしか考えられません。

  1. ブロックはloginControllerオブジェクト(__blockタイプ修飾子)を保持しません。ブロックが非同期で実行された場合、それ以外の場合に強制終了された場合、loginControllerは使用できなくなる可能性があります。したがって、何をしたい場合でも、ブロック内でアクセスできなくなり、アプリがクラッシュします。これは、loginViewDidSubmitの送信後にコントローラーが強制終了された場合に発生する可能性があります。

  2. これはおそらくあなたの状況かもしれないと思います:loginControllerはそのデリゲートオブジェクトを呼び出します。デリゲートメソッドは、コントローラーを強制終了するコールバックブロックを同期的に呼び出すことになります。コントローラは、デリゲートメソッドを呼び出した後に動作していることが期待されます。デリゲートメソッド内でそれを強制終了すると、クラッシュが発生する可能性があります。これが問題であることを確認するには、デリゲートメソッドでloginControllerをnilし、デリゲートを呼び出した後にコントローラーにNSLogステートメントを配置します。ブロックを気にしないでください。そこでクラッシュが発生します。

おそらく、コードを貼り付けると、さらに役立つ可能性があります。

私のベスト。

于 2011-09-13T17:07:14.063 に答える