AVPlayer ulega awarii po wielokrotnym odtwarzaniu -
Próbuję utworzyć aplikację, która odtwarza filmy z pliku za pomocąAVFoundation
. Filmy są wyświetlane w widoku, do którego można uzyskać dostęp, dotykając wiersza w widoku tabeli nadrzędnej. Prawdziwa aplikacja będzie miała wideo dla każdego wiersza, ale w tej chwili używam tylko jednego do testowania.
Po uruchomieniu na symulatorze aplikacja jest w porządku, ale po uruchomieniu na urządzeniu (pod ios 5.1) wideo jest odtwarzane ok. 5 razy, a następnie nieprzewidywalnie ulega awarii na wiele sposobów. Najczęściej ładuje się widok wideo, ale sam film nie gra, ale czasami dostajęEXC_BAD_ACCESS
nacoremedia.remote
wątek, narzekający na obiekty przydzielane bez puli autorelease. Dodałem@autoreleasepool
zablokuj zawijanie kodu uruchamiającego AVPlayera, ale to chyba nie pomaga.
Zastanawiam się, czy dzieje się tak, że GCD tworzy wiele wątków w głównej kolejce, aby odtwarzać przedmioty, ale nie kończą się.
Kluczowym pytaniem jest więc, jak wyczyścić zbędne wątki GCD, na których działa AVPlayer, jeśli użytkownik kliknie przycisk Wstecz w widoku wideo. O ile to możliwe, zastosowałem przykładowy kod podany w AppleAVFoundation
dokumentacjatutaj Dodałem trochę logowania i (jak wspomniano powyżej) i@autoreleasepool
zablokuj wewnątrz jednego z bloków GCD - poza tym nie zmieniłem kodu.
TheviewDidLoad
metoda jest następująca:
<code>-(void)viewDidLoad{ [super viewDidLoad]; NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"TestLapCar2Vid" withExtension:@"m4v"]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; NSString *tracksKey = @"tracks"; [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:tracksKey] completionHandler: ^{ dispatch_async(dispatch_get_main_queue(), ^{ @autoreleasepool { NSError *error = nil; AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error]; if(status == AVKeyValueStatusLoaded){ avPlayerItem = [AVPlayerItem playerItemWithAsset:asset]; [avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:&ItemStatusContext]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:avPlayerItem]; avPlayer = [AVPlayer playerWithPlayerItem:avPlayerItem]; [videoView setPlayer:avPlayer]; NSLog(@"Asset loaded"); [avPlayer play]; } else{ NSLog(@"The asset's tracks were not loaded"); } } }); }]; </code>
}
TheviewWillDisappear
metoda to:
<code>-(void)viewWillDisappear:(BOOL)animated{ NSLog(@"view will disappear called"); [super viewWillDisappear:animated]; dispatch_async(dispatch_get_main_queue(), ^{ [avPlayer pause]; [avPlayerItem removeObserver:self forKeyPath:@"status"]; [[NSNotificationCenter defaultCenter]removeObserver:self]; NSLog(@"Race timeline nav controller has %d sub controllers",self.navigationController.childViewControllers.count); avPlayerItem = nil; avPlayer = nil; videoView = nil; dataStore = nil; pkReader = nil; receivedData = nil; revDial = nil; speedDial = nil; mapView = nil; throttle = nil; NSLog(@"releasing stuff"); }); </code>
}
Przez większość dnia zmagałem się z tym - każda pomoc byłaby wdzięczna