Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Just change the first line to:</p> <pre><code>__block MyVideoPlayer *videoPlayer = [[[MyVideoPlayer alloc] init] autorelease]; </code></pre> <p>The reason this works is because:</p> <blockquote> <p>In a reference-counted environment, by default when you reference an Objective-C object within a block, it is retained. This is true even if you simply reference an instance variable of the object. Object <strong>variables marked with</strong> the <strong>__block</strong> storage type modifier, however, <strong>are not retained</strong>.</p> </blockquote> <p>See Apple's Documentation on <a href="https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW3" rel="nofollow">Object and Block Variables</a></p> <h2>But Why Wasn't It Being Released To Begin With?</h2> <p>Simple explanation is that after the <code>completionBlock</code> executes, it is not being released. It is being released later in <code>dealloc</code>, thus all the variables it is retaining are still retained. This makes sense since it is possible to execute a block as many times as you wish until it is released. </p> <p>I've seen this behavior before where an object that owns a block is referenced in the block and releases the block in dealloc, which prevents the object from ever being released. <strong>The solution is to weakly reference the object that owns the block.</strong> This way the owning type, like <code>MyVideoPlayer</code>, reaches <code>dealloc</code>, which subsequently releases the block (<code>completionBlock</code> in this example).</p> <p>An alternative to using the <code>__block</code> keyword to avoid retaining a type is to wrap the object in an <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsvalue_Class/Reference/Reference.html" rel="nofollow"><code>NSValue</code></a> by using the <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/nsvalue_Class/Reference/Reference.html#//apple_ref/doc/uid/20000177-valueWithNonretainedObject_" rel="nofollow"><code>valueWithNonretainedObject:</code></a> and <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/nsvalue_Class/Reference/Reference.html#//apple_ref/doc/uid/20000177-nonretainedObjectValue" rel="nofollow"><code>nonretainedObjectValue</code></a> methods. For instance:</p> <pre><code>MyVideoPlayer *videoPlayer = [[[MyVideoPlayer alloc] init] autorelease]; NSValue *videoPlayerRef = [NSValue valueWithNonretainedObject:videoPlayer]; [videoPlayer canPlayAsset:(MyVideoAsset *)asset completionBlock:^(BOOL isAssetPlayable) { if (isAssetPlayable) { MyVideoPlayer *tempVideoPlayer = (MyVideoPlayer*)[videoPlayerRef nonretainedObjectValue]; [tempVideoPlayer playAsset:asset]; [self presentModalViewController:tempVideoPlayer animated:YES]; } }]; </code></pre> <h2>Edit / Conversation</h2> <p>This section is to expand further into why the block is not being released. I am going to include what I assume is happening behind <code>MyVideoPlayer</code>. It would be great to see actual code, but this should suffice.</p> <p><strong>Header file...</strong></p> <pre><code>typedef void(^MyVideoPlayerCompletionBlock)(BOOL isAssetPlayable); @interface MyVideoPlayer : NSObject @property(nonatomic, copy) MyVideoPlayerCompletionBlock completion; ... // other property definitions (or ivars) -(void)canPlayAsset:(MyVideoAsset*)asset completionBlock:(MyVideoPlayerCompletionBlock)completion; ... // other methods defined @end </code></pre> <p><strong>Implementation...</strong></p> <pre><code>@implementation MyVideoPlayer @synthesize completion = _completion; -(void)dealloc { // Note: Block is released in dealloc like any other property or variable [_completion release], _completion = nil; ... // other variables and properties not shown here are released [super dealloc]; } -(void)canPlayAsset:(MyVideoAsset*)asset completionBlock:(MyVideoPlayerCompletionBlock)completion { ... // Does something with asset. Plays it, stores it, whatever // Saves completion block to call at a later time. // Note that this code could alternatively look like // _completion = [completion copy]; // Blocks are usually copied and not retained self.completion = completion; } </code></pre> <p><strong>... AT SOME POINT THE COMPLETION BLOCK FIRES ...</strong> <em>(probably in an event handler or some sort)</em></p> <pre><code>-(void)SomeEventHandlerOrFuncThatCallsCompletionInMyVideoPlayer { // Time to call completion! if (self.completion) { self.completion(YES); // OR no, doesn't matter // // WHOA! :: self.completion is not released // // i.e. self.completion is not nil, and all // variables inside it are still retained // because calling a block doesn't also // release the block. To do that you would // need to do: self.completion = nil; // AFTER calling: self.completion(...); // // SO... // // Because the block was not released, it is // still retaining variables (such as the current // instance of MyViewPlayer). Note that the // Block will never be released until dealloc // is called. :( So..., if you want the block // to retain the current MyViewPlayer until // execution of the completion block is over, you // will want to call: self.completion = nil; // to release the block and all associated variables // after calling the completion block. } } @end </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload