如何预加载AVPlayerViewController并动态切换视频源以避免黑屏?
Absolutely! Preinitializing your AVPlayerViewController and reusing it with different video sources is not only possible but also the ideal fix for the black screen flash you're encountering. The root cause of the flash is the overhead of creating a new AVPlayer and AVPlayerViewController every time you present—reusing these objects eliminates that delay entirely.
Step-by-Step Implementation
1. Declare Global Properties
Keep your player and view controller as instance properties (you already have this, but we'll initialize them upfront):
@interface YourViewController () @property (nonatomic, strong) AVPlayer *player; @property (nonatomic, strong) AVPlayerViewController *playerViewController; @property (nonatomic, strong) AVPlayerLooper *currentLooper; // Optional: For looping animations @end
2. Preinitialize in viewDidLoad
Set up the player and view controller once when your page loads—this avoids repeated initialization overhead:
- (void)viewDidLoad { [super viewDidLoad]; // Initialize player with a placeholder URL (we'll replace this later) self.player = [AVPlayer playerWithURL:[NSURL URLWithString:@""]]; // Preconfigure the player view controller self.playerViewController = [[AVPlayerViewController alloc] init]; self.playerViewController.player = self.player; self.playerViewController.showsPlaybackControls = NO; // Optional: Set presentation style if needed self.playerViewController.modalPresentationStyle = UIModalPresentationFullScreen; }
3. Modify playAnimation to Reuse Objects
Instead of creating new player and controller instances, just swap out the AVPlayerItem when a new video is requested:
- (void)playAnimation:(NSString *)filePath { NSURL *videoURL = [NSURL fileURLWithPath:filePath]; AVPlayerItem *newPlayerItem = [AVPlayerItem playerItemWithURL:videoURL]; // Remove existing observer to avoid memory leaks if (self.player.currentItem) { [self.player.currentItem removeObserver:self forKeyPath:@"status"]; } // Replace the current player item [self.player replaceCurrentItemWithPlayerItem:newPlayerItem]; // Observe the item's status to ensure it's ready before playing __weak typeof(self) weakSelf = self; [newPlayerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; // Present or reuse the view controller if (self.presentedViewController != self.playerViewController) { [self presentViewController:self.playerViewController animated:NO completion:^{ [weakSelf checkAndPlayIfReady:newPlayerItem]; }]; } else { [self checkAndPlayIfReady:newPlayerItem]; } // Optional: Set up looping if your animation needs to repeat self.currentLooper = [AVPlayerLooper playerLooperWithPlayer:self.player templateItem:newPlayerItem]; }
4. Helper Methods for Status Checking & Cleanup
Add these methods to handle playback readiness and avoid memory leaks:
- (void)checkAndPlayIfReady:(AVPlayerItem *)item { switch (item.status) { case AVPlayerItemStatusReadyToPlay: [self.player play]; break; case AVPlayerItemStatusFailed: NSLog(@"Failed to load video: %@", item.error.localizedDescription); // Add error handling here (e.g., alert the user) break; case AVPlayerItemStatusUnknown: // Still loading—wait for KVO update break; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"status"]) { AVPlayerItem *item = (AVPlayerItem *)object; [self checkAndPlayIfReady:item]; [item removeObserver:self forKeyPath:@"status"]; } } - (void)dealloc { // Clean up remaining observers if (self.player.currentItem) { [self.player.currentItem removeObserver:self forKeyPath:@"status"]; } }
Key Notes
- No More Black Screens: By reusing the preinitialized view controller and player, the video's first frame loads before presentation, eliminating the flash.
- Local Video Optimization: Since your videos are stored locally (Bundle or sandbox), load times are already fast—this approach makes them virtually instant.
- Looping Support: The
AVPlayerLooperensures your animation repeats seamlessly (remove this if you don't need looping). - Memory Safety: Always remove KVO observers to prevent crashes and memory leaks.
内容的提问来源于stack exchange,提问作者Niall Kiddle

