AVPlayer 在我的阵列中无法正常工作 - swift

AVPlayer not working correct w/ my array - swift

我目前有 UI Collection 从您的相机胶卷中检索数据以将您的所有视频加载到 collection。现在我要做的是,当您 select collection 中的视频在我的自定义 UIView 中播放时,它是一个 AVPlayer;一切都很好,除了当我播放视频时它并不总是播放正确的视频我已将视频网址附加到其中。它通常只会播放库中的随机视频,有时会导致应用程序崩溃,指向我附加视频 URL 的位置并说 "fatal out of range"。我似乎无法弄清楚为什么会这样。它正确打印出数组的值和计数;所以我认为这与我检索视频的方式有关。

这里是我获取视频的地方:

 let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat

let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions) {
    if fetchResult.count > 0 {
        for i in 0..<fetchResult.count{

            //Used for fetch Image//
            imgManager.requestImage(for: fetchResult.object(at: i) as PHAsset , targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFit, options: requestOptions, resultHandler: {
                image, error in
                let imageOfVideo = image! as UIImage
                self.imageArray.append(imageOfVideo)
            })
            //Used for fetch Video//
            imgManager.requestAVAsset(forVideo: fetchResult.object(at: i) as PHAsset, options: PHVideoRequestOptions(), resultHandler: {(avAsset, audioMix, info) -> Void in
                if let asset = avAsset as? AVURLAsset {
                    let videoData = NSURL(string: "\(asset.url)")
                    let duration : CMTime = asset.duration
                    let durationInSecond = CMTimeGetSeconds(duration)
                    print(durationInSecond)
                    self.videoArray.append(videoData!)
                    print(self.videoArray)
                }

            })
        }

    }
    else{
        //showAllertToImportImage()//A function to show alert
    }
}
}

每个单元格的加载 -> 不过我不认为这很重要

     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! VideoSelectionCVCell

    cell.uploadedFile.image = imageArray[indexPath.row]
    return cell
}

didSelect:->> 我认为这就是问题所在

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    displayView.frame = CGRect(x: self.view.frame.size.width / 2, y: self.view.frame.size.height / 2, width:self.view.frame.size.width / 1.15, height: self.view.frame.size.height / 1.3)
    displayView.center = view.center
    displayView.backgroundColor = UIColor.clear
    displayView.layer.cornerRadius = displayView.layer.frame.size.width / 10
    displayView.layer.borderColor = UIColor.black.cgColor
    displayView.layer.borderWidth = 4
    //displayView.avPlayerLayer.cornerRadius = displayView.avPlayerLayer.frame.size.width/10
    displayView.url = videoArray[indexPath.row]
}

计数

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return imageArray.count
}

自定义播放器:

class VideoPlayBack: UIView {

var url: NSURL!
var avPlayer: AVPlayer!
var avPlayerLayer: AVPlayerLayer!
var cancelButton: UIButton!

// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {

    self.backgroundColor = UIColor.black

    avPlayer = AVPlayer(url: url! as URL)
    avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.none
    avPlayerLayer = AVPlayerLayer(player: avPlayer)

    NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: avPlayer.currentItem)


    avPlayerLayer.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
    //avPlayerLayer.frame = self.layer.bounds
    self.layer.addSublayer(avPlayerLayer)
    avPlayer.play()


}

func playerItemDidReachEnd(_ notification: Notification) {
    let playerItem = notification.object as! AVPlayerItem
    playerItem.seek(to: kCMTimeZero)
}
}

这里是完整的 collection 视图 class 以防万一。

https://paste.ee/p/JgZSu

同样,我认为这与我添加和检索视频的方式有关。

我相信创建一个小的 class 或结构(即媒体)来保存图像和视频并创建一个媒体数组以用于您的

会更安全=19=]观点。这是因为 2 种获取方法是异步的,因此您永远不知道 video/image 组合将分配给哪个索引。此外,尝试嵌套异步调用,以便同一媒体实例用于两个调用以保持数据一致性。

这是一个未经测试的例子:

struct Media {
    var image:UIImage?
    var videoURL:URL?
}

var mediaArray = [Media]()

for i in 0..<fetchResult.count{
    let mediaItem = Media()
    //Used for fetch Image//
    imgManager.requestImage(for: fetchResult.object(at: i) as PHAsset , targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFit, options: requestOptions, resultHandler: {
        image, error in
        let imageOfVideo = image! as UIImage
        mediaItem.image = imageOfVideo;
        //Used for fetch Video//
        imgManager.requestAVAsset(forVideo: fetchResult.object(at: i) as PHAsset, options: PHVideoRequestOptions(), resultHandler: {(avAsset, audioMix, info) -> Void in
            if let asset = avAsset as? AVURLAsset {
                let videoData = URL(string: "\(asset.url)")
                let duration : CMTime = asset.duration
                let durationInSecond = CMTimeGetSeconds(duration)
                print(durationInSecond)
                mediaItem.videoURL = videoData!
                self.mediaArray.append(mediaItem)
            }

        })
    })
} 

然后使用媒体数组填充您的 collectionView。不要忘记始终解包数据。不要使用强制解包,你将(几乎)永远不会崩溃