2011-11-16 1 views
10

私はプログラミングとObjective-Cには非常に新しいので、何が間違っているかを試しています私のコード。私はブロックについて少しは読んだことがありますが、私がこれまでに読んだことが私のコードにどのように関係しているか分かりません。iOS 5 TwitterフレームワークとcompletionHandlerブロック - 「このブロック内で 'self'を強く捕捉すると保持サイクルにつながる」

私のコードでは、iOS 5 Twitter Frameworkが使用されています。 Appleが提供するほとんどのサンプルコードを使用しているため、最初に補完ハンドラのブロックを使用しているという手がかりはありませんでした。

今、私は「1.ブロックが強く被写体によって保持されたオブジェクトによって保持されます」と、このブロックで強く「キャプチャ 『自己』につながる可能性が高いと言ってXcodeの4からこれらの2つのメッセージを取得します保持サイクル "。

基本的に、私がやったことは自分の完了ハンドラ(TWTweetComposeViewControllerResultCancelled & TWTweetComposeViewControllerResultDoneとswitch文)で使用されるコードのアップルを削除することであり、私の[imagePickerController sourceType]とif文を使用していました。

したがって、画像がツイートに追加された後にsendTweetが呼び出されます。

私は、なぜこれが起こっているのか、どうすれば解決できるのか誰かが私に説明できることを願っています。また、補完ハンドラコードをブロックではなくメソッドに入れることはできますか?

- (void)sendTweet:(UIImage *)image 
{ 
    //adds photo to tweet 
    [tweetViewController addImage:image]; 

    // Create the completion handler block. 
    //Xcode: "1. Block will be retained by an object strongly retained by the captured object" 
    [tweetViewController setCompletionHandler: 
          ^(TWTweetComposeViewControllerResult result) { 
      NSString *alertTitle, 
        *alertMessage, 
        *otherAlertButtonTitle, 
        *alertCancelButtonTitle; 

      if (result == TWTweetComposeViewControllerResultCancelled) 
      { 
       //Xcode: "Capturing 'self' strongly in this block is likely to lead to a retain cycle" 
       if ([imagePickerController sourceType]) 
       { 
        alertTitle = NSLocalizedString(@"TCA_TITLE", nil); 
        alertMessage = NSLocalizedString(@"TCA_MESSAGE", nil); 
        alertCancelButtonTitle = NSLocalizedString(@"NO", nil); 
        otherAlertButtonTitle = NSLocalizedString(@"YES", nil); 

        //user taps YES 
        UIAlertView *alert = [[UIAlertView alloc] 
              initWithTitle:alertTitle 
                message:alertMessage 
                delegate:self // Note: self 
             cancelButtonTitle:alertCancelButtonTitle 
             otherButtonTitles:otherAlertButtonTitle,nil]; 
        alert.tag = 1; 
        [alert show];     
       }    
      } 

答えて

21

基本的な問題は、ブロック内でselfを使用していることです。ブロックはオブジェクトによって保持され、ブロック自体もオブジェクトを保持します。だから、あなたは保持サイクルを持っているので、両方ともそれらに向かって指す参照があるので、おそらく両方が解放されることはありません。 Fortunalyには簡単な回避策があります:

自己への弱い参照を使用することで、ブロックはオブジェクトを保持しなくなります。その後、オブジェクトは後でブロックを解放れる解放することができます(適切な型にMyClassを設定):

// before your block 
__weak MyObject *weakSelf = self; 

をあなたのブロックの中にあなたが今weakSelfの代わりself使用することができます。これは、ARCを使用しているiOS 5のみに適用されます。

これを見ると、How do I avoid capturing self in blocks when implementing an API?についての長い説明もあり、iOS 4ではこれを回避する方法とARCなしで説明しています。

+0

ありがとうございました!私は総初心者なので、実際にこれを実装する方法を考え出すのに問題がありました。最後に私は__weak UIImagePickerController * weakSelf = imagePickerControllerを使用しました。 if文をif([weakSelf sourceType])に変更します。 Xcode 4は私にもうエラーを表示していないので、正しいことをしたと思います。 (?) – iMaddin

+0

+1 @Dennisは答えに感謝します。 「__block」が使用されている場合も説明してください。例iには、 のような構文があります。 __block HomeViewController * weakSelf = self; – HDdeveloper

3

あなたのブロックは、selfをUIAlertViewの代理人として使用しているため、selfを保持しています。 selfもブロックを保持している場合、ブロックは互いに保持されており、保持サイクルが作成されます。

__block WhateverTypeSelfIs *nonRetainedSelfForBlock = self; 
[tweetViewController setCompletionHandler: 

UIAlertView *alert = [[UIAlertView alloc] 
           initWithTitle:alertTitle 
           message:alertMessage 
           delegate:nonRetainedSelfForBlock 
           cancelButtonTitle:alertCancelButtonTitle 
           otherButtonTitles:otherAlertButtonTitle,nil]; 

チェックApple docs、セクションオブジェクトとブロック変数をお試しください。 __blockを使用しない限り、ブロック内で参照されるオブジェクトは保持されます。

+0

ブロック内の私のUIAlertViewに何か問題があったことを指摘してくれてありがとう。私はARCを使用しているので、Xcodeは私に__blockを使用できないと言ったと思います。私はTriPhoenixが言及したように代わりに__weakを使用しました。ありがとう! – iMaddin

+0

+1 @Terry Wilcox、 "__block"と "__weak"の違いを説明してください。ありがとう – HDdeveloper

+0

@HDdeveloper http://stackoverflow.com/questions/11773342/what-the-difference-between-weak-and-block-reference –

0

警告を取り除くにはかなり驚くべき方法があります。保持サイクルを作成していないと確信している場合や、後で完了ハンドラを設定しないと完了ハンドラをnilに設定した場合は、自分で破ることが確実な場合にのみ、これを実行してください。インターフェイスを制御できる場合は、メソッドの名前を "set"で始まらないように変更します。コンパイラは、メソッド名が "set"で始まる場合にのみ、この警告を出すようです。

1

私は他の場所で見たことによると、「弱い」はARC準拠のコードでは機能しません。代わりに「 _unsafe_unretained」を使用する必要があります。これはAppleのサンプルアプリ「AVPlayerDemo」で「このブロックに強くキャプチャすると「保持」サイクルにつながる」という警告を修正するためです。

__unsafe_unretained id unself = self; 
mTimeObserver = [mPlayer addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC) 
          queue:NULL /* If you pass NULL, the main queue is used. */ 
          usingBlock:^(CMTime time) 
             { 
              /* 'unself' replaced 'self' here: */ 
              [unself syncScrubber]; 
             }]; 
関連する問題