5
votes

I am developing a project on iOS 7 using ARC, I want to release a private property when the viewController is released
Here is the TestViewController that is presented as a modal view controller, setting a value to the private property testAVPlayer in viewDidLoad:

//TestViewController.m
#import "TestAVPlayer.h"
@interface TestViewController () {
    TestAVPlayer *testAVPlayer;
}

@end

- (void)viewDidLoad
{
    [self setupPlayer];
}

- (void)setupPlayer {
    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"music" withExtension:@"mp3"]];
    testAVPlayer = [TestAVPlayer playerWithPlayerItem:item];

    [testAVPlayer setActionAtItemEnd:AVPlayerActionAtItemEndNone];
    [testAVPlayer play];
}

- (void)dealloc {
    NSLog(@"dealloc TestViewController: %@", self);
}

TestAVPlayer is a subclass of AVPlayer, I put a NSLog into the dealloc

// TestAVPlayer.h
#import <AVFoundation/AVFoundation.h>

@interface TestAVPlayer : AVPlayer

@end

//  TestAVPlayer.m
#import "TestAVPlayer.h"

@implementation TestAVPlayer

- (void)dealloc {
    NSLog(@"dealloc testAVPlayer: %@", self);
}
@end

When TestViewController is dismissed, the testAVPlayer seems never be released, I see the "dealloc TestViewController", but there is no "dealloc testAVPlayer" in console log

5
you dont need to dealloc thats the whole point of ARC...meda
@meda yes, but dealloc should still get called when released by ARC. Something must be retaining the object, but I'm afraid there is not enough to go on here.Brad Allred
You might retain it somewhere in block or use repeating timer without invalidation. It's not enough info now.Timur Kuchkarov
Does instruments tell you the object is not being released?quellish
I edited my question, provide the codes I'm using actually, the testAVPlayer is only placed in setupPlayer, nowhere else.bandw

5 Answers

10
votes

I tried your code, the problem is that even if you call [TestAVPlayer playerWithPlayerItem:item] the TestAVPlayer class doesn't have such method, so it will call playerWithPlayerItem: function from the AVPlayer base class, which will return an instance of the AVPlayer class instead of the TestAVPlayer class. The compiler won't give you any warning because the playerWithPlayerItem: method returns a type of id. If you check this with the debugger you'll see that the private variable's type is not TestAVPlayer:

enter image description here

The dealloc of the TestAVPlayer will never be called as no such object was created. The AVPlayer instance gets deallocated when the TestViewController is deallocated. You can check this by using Instruments or simply adding a Symbolic Breakpoint to [AVPlayer dealloc].

Select the Breakpoint Navigator and click on the + button and add a Symbolic Breakpoint.

Write [AVPLayer dealloc] to the Symbol field and press Enter. When you run the application and the TestViewController gets deallocated then you will see that the breakpoint will be hit, hence the AVPlayer really gets deallocated.

5
votes

You are using a class factory method to initialize your object, which means that you do not own the testAVPlayer object and thus are not responsible for releasing it.

See Class Factory Methods from the Concepts in Objective-C Programming guide for more details.

If you indeed want to own and control the lifetime of this object, use the following initializer:

testAVPlayer = [[TestAVPlayer alloc] initWithPlayerItem:item];

and your dealloc method will be called.

2
votes

testAVPlayer = [AVPlayer playerWithPlayerItem:playerItem];

You are using AVPlayer, not your TestAVPlayer.

1
votes

Try implementing - viewDidUnload then nil the testAVPlayer:

- (void) viewDidUnload
{
    [super viewDidUnload];
    testAVPlayer = nil;
} 
1
votes

Although you are calling it as [TestAVPlayer playerWithPlayerItem:item], you are really getting back an instance of AVPlayer, not TestAVPlayer. In fact, the AVPlayer instance you created really IS getting deallocated. You won't be able to see your log in dealloc because an instance of that class is never created.

As suggested by another, replace [TestAVPlayer playerWithPlayerItem:item] with [[TestAVPlayer alloc] initWithPlayerItem:item]; and you should start seeing your logs.