Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 每个AVPlayerLayer一个AVPlayer对多个AVPlayer_Ios_Objective C_Cocoa_Avfoundation - Fatal编程技术网

Ios 每个AVPlayerLayer一个AVPlayer对多个AVPlayer

Ios 每个AVPlayerLayer一个AVPlayer对多个AVPlayer,ios,objective-c,cocoa,avfoundation,Ios,Objective C,Cocoa,Avfoundation,我正在尝试创建类似Vine的应用程序。我有一个集合视图,其中每个项目都包含一个带有AVPlayerLayer和AVPlayer实例的视图,相应地,AVPlayer已附加到该层 一切都很好 但是我想知道,如果我只为集合视图中包含的每个AVPlayerLayer使用一个AVPlayer实例,可能会更好。如果我想显示下一个项目,我将从当前项目层删除AVPlayer实例,并将其移动到下一个项目层。毕竟我调用了[videoPlayer replacementCurrentItemwithPlayerIte

我正在尝试创建类似Vine的应用程序。我有一个集合视图,其中每个项目都包含一个带有
AVPlayerLayer
AVPlayer
实例的视图,相应地,AVPlayer已附加到该层

一切都很好

但是我想知道,如果我只为集合视图中包含的每个
AVPlayerLayer
使用一个
AVPlayer
实例,可能会更好。如果我想显示下一个项目,我将从当前项目层删除
AVPlayer
实例,并将其移动到下一个项目层。毕竟我调用了
[videoPlayer replacementCurrentItemwithPlayerItem:newItem]


也许有人知道更好的解决方案,可以获得与Vine应用程序相同的性能。

以下是我如何在集合视图中做到这一点的:

//
//  ViewController.m
//  VideoWall
//
//  Created by James Alan Bush on 6/13/16.
//  Copyright © 2016 James Alan Bush. All rights reserved.
//

#import "ViewController.h"
#import "AppDelegate.h"

static NSString *kCellIdentifier = @"Cell Identifier";

@interface ViewController () {
    dispatch_queue_t dispatchQueueLocal;
}

@end

@implementation ViewController

- (id)initWithCollectionViewLayout:(UICollectionViewFlowLayout *)layout
{
    if (self = [super initWithCollectionViewLayout:layout])
    {
        [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kCellIdentifier];
        dispatchQueueLocal = dispatch_queue_create( "local session queue", DISPATCH_QUEUE_CONCURRENT );
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.collectionView setDataSource:self];
    [self.collectionView setContentSize:CGSizeMake(AppDelegate.sharedAppDelegate.width, AppDelegate.sharedAppDelegate.height)];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)dealloc {
    [super dealloc];
}

#pragma mark <UICollectionViewDataSource>

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

#pragma mark - UICollectionViewDataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return AppDelegate.sharedAppDelegate.assetsFetchResults.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    UICollectionViewCell *cell = (UICollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];
    [CATransaction begin];
    [CATransaction setCompletionBlock:^{
        cell.contentView.layer.sublayers = nil;
        dispatch_release(dispatchQueueLocal);
    }];
    dispatch_retain(dispatchQueueLocal);
    dispatch_async( dispatchQueueLocal, ^{
        [self drawPlayerLayerForCell:cell atIndexPath:indexPath];
    });
    [CATransaction commit];

    return cell;
}

- (void)drawPlayerLayerForCell:(UICollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    void (^drawPlayerLayer)(UICollectionViewCell*, NSIndexPath*) = ^(UICollectionViewCell* cell, NSIndexPath* indexPath) {
        [AppDelegate.sharedAppDelegate.imageManager requestPlayerItemForVideo:AppDelegate.sharedAppDelegate.assetsFetchResults[indexPath.item] options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if(![[info objectForKey:PHImageResultIsInCloudKey] boolValue]) {
                    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:[AVPlayer playerWithPlayerItem:playerItem]];
                    [playerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
                    [playerLayer setBorderColor:[UIColor whiteColor].CGColor];
                    [playerLayer setBorderWidth:1.0f];
                    [playerLayer setFrame:cell.contentView.bounds];

                    [cell.contentView.layer addSublayer:playerLayer];
                    [(AVPlayer *)playerLayer.player play];

                } else {
                    [AppDelegate.sharedAppDelegate.imageManager requestImageForAsset:AppDelegate.sharedAppDelegate.assetsFetchResults[indexPath.item]
                                                                          targetSize:CGSizeMake(AppDelegate.sharedAppDelegate.flowLayout.itemSize.width, AppDelegate.sharedAppDelegate.flowLayout.itemSize.height)
                                                                         contentMode:PHImageContentModeAspectFill
                                                                             options:nil
                                                                       resultHandler:^(UIImage *result, NSDictionary *info) {
                                                                           dispatch_async(dispatch_get_main_queue(), ^{
                                                                               cell.contentView.layer.contents = (__bridge id)result.CGImage;
                                                                           });
                                                                       }];
                }
            });
        }];
    };
    drawPlayerLayer(cell, indexPath);
}

@end

这是你需要的仅有的两个文件;没有NIB/XIB。

你知道什么更好吗?@Eric,是的,我两个都试过,大部分时间我都用一台AVPlayer播放视频,一切都很棒。但是我有一个小问题(球员之间的管理,没关系)。后来我重构了代码,现在我用一个播放器处理一个项目,一切都很好。在同一时刻大约有2-4个AVPlayer实例。@tikhop您是否使用该单元格作为播放器的代理?换句话说,您是否为该单元格指定了cell.player type属性?@kevin肯定,该单元格是玩家实例的代理,而且每个单元格都包含自己的玩家实例,当某个单元格想要玩玩家时,该玩家将变为活动状态,因此前一个玩家stopsHi@tikhop,一个
AVPlayer
与多个
AVPlayerLayer
的比率有效吗?嘿,詹姆斯!这些单元是否正在被释放,或者它们有某种阻止释放的保留周期?换句话说,如果我滚动大约100个视频,它们会全部保留在内存中还是只保留当前正在播放的一个?
//
//  AppDelegate.m
//  VideoWall
//
//  Created by James Alan Bush on 6/13/16.
//  Copyright © 2016 James Alan Bush. All rights reserved.
//

#import "AppDelegate.h"
#import "ViewController.h"

@implementation AppDelegate

+ (AppDelegate *)sharedAppDelegate
{
    return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch

    self.width = [[UIScreen mainScreen] bounds].size.width / 2.0;
    self.height = [[UIScreen mainScreen] bounds].size.height / 4.0;

    self.window                    = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = [self viewController];
    self.window.rootViewController.view = self.viewController.view;


    [self.window makeKeyAndVisible];

    return YES;
}

- (ViewController *)viewController {
    ViewController *c = self->_viewController;
    if (!c) {
        c = [[ViewController alloc] initWithCollectionViewLayout:[self flowLayout]];
        [c.view setFrame:[[UIScreen mainScreen] bounds]];
        self->_viewController = c;
    }
    return c;
}

- (UICollectionViewFlowLayout *)flowLayout {
    UICollectionViewFlowLayout *v = self->_flowLayout;
    if (!v) {
        v = [UICollectionViewFlowLayout new];
        [v setItemSize:CGSizeMake(AppDelegate.sharedAppDelegate.width, AppDelegate.sharedAppDelegate.height)];
        [v setSectionInset:UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)];
        [v setMinimumLineSpacing:0.0];
        [v setMinimumInteritemSpacing:0.0];
        [v setEstimatedItemSize:CGSizeMake(AppDelegate.sharedAppDelegate.width, AppDelegate.sharedAppDelegate.height)];
        self->_flowLayout = v;
    }
    return v;
}

- (PHCachingImageManager *)imageManager {
    PHCachingImageManager *i = self->_imageManager;
    if (!i) {
        i = [[PHCachingImageManager alloc] init];
        self->_imageManager = i;
    }
    return i;
}

- (PHFetchResult *)assetsFetchResults {
    PHFetchResult *i = self->_assetsFetchResults;
    if (!i) {
        PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumVideos options:nil];
        PHAssetCollection *collection = smartAlbums.firstObject;
        if (![collection isKindOfClass:[PHAssetCollection class]])
            return nil;
        PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
        allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
        i = [PHAsset fetchAssetsInAssetCollection:collection options:allPhotosOptions];
        self->_assetsFetchResults = i;
    }
    return i;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end