Как переместить ссылку на PHAsset из All Photos/Camera Roll в определенную коллекцию PHAssetCollection?

Я использую OpalImagePickerController для выбора изображений/видео из All Photos/Camera Roll, и это дает мне [PHAsset], что нормально, но я хотел добавить их в определенный альбом в приложении Photos, и я использую для этого код ниже:

@objc func btnAddTapped() {
    
    guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
        //Show error to user?
        return
    }

    //Example Instantiating OpalImagePickerController with Closures
    let imagePicker = OpalImagePickerController()

    //Present Image Picker
    presentOpalImagePickerController(imagePicker, animated: true, select: { (selectedAssets) in
        
        imagePicker.dismiss(animated: true, completion: nil)
        
        let sdLoader = SDLoader()
        sdLoader.startAnimating(atView: self.view)
        
        let options = PHImageRequestOptions()
        options.deliveryMode = .highQualityFormat
        options.isNetworkAccessAllowed = true
        
        let videoOptions = PHVideoRequestOptions()
        videoOptions.deliveryMode = .highQualityFormat
        videoOptions.isNetworkAccessAllowed = true
        
        let myGroup = DispatchGroup()
        
        for item in selectedAssets {
            
            myGroup.enter()
            
            let asset = item
            if asset.mediaType == PHAssetMediaType.video {
                //Fetch URL if its a video
                PHCachingImageManager().requestAVAsset(forVideo: asset, options: videoOptions) { (playerItem, audioMix, args) in
                    
                    if let videoAVAsset = playerItem as? AVURLAsset {
                        let url = videoAVAsset.url
                        PhotoManager.instance.storeVideoToSpecificAlbum(videoURL: url, to: self.asset, completion: {_ in
                            print("video stored")
                            myGroup.leave()
                        })
                    }
                }
                
            } else {
                //Image
                PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options, resultHandler: {(data, string, orientation, any) in
                    if let data = data {
                        DispatchQueue.main.async {
                            if let img = UIImage(data: data) {
                                PhotoManager.instance.storeImageToSpecificAlbum(image: img, to: self.asset, completion: {_ in
                                    print("Image stored")
                                    myGroup.leave()
                                })
                            }
                        }
                    }
                })
            }
        }
        
        myGroup.notify(queue: .main) {
            sdLoader.stopAnimation()
            self.fetchImagesFromAlbum()
        }
        
    }, cancel: {
        print("cancel tapped")
    })
}

И вот вспомогательные методы, которые я использую:

//Store Video
func storeVideoToSpecificAlbum(videoURL: URL, to album: PHAssetCollection, completion: @escaping (PHAssetCollection?) -> Void) {
    
    PHPhotoLibrary.shared().performChanges({
        let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
        let placeholder = assetRequest?.placeholderForCreatedAsset
        guard let _placeholder = placeholder else { completion(nil); return }
        
        let albumChangeRequest = PHAssetCollectionChangeRequest(for: album)
        albumChangeRequest?.addAssets([_placeholder] as NSFastEnumeration)
    }) { success, error in
        completion(album)
    }
}

//Store Image
func storeImageToSpecificAlbum(image: UIImage, to album: PHAssetCollection, completion: @escaping (PHAssetCollection?) -> Void) {
    
    PHPhotoLibrary.shared().performChanges({
        let assetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
        let placeholder = assetRequest.placeholderForCreatedAsset
        guard let _placeholder = placeholder else { completion(nil); return }
        
        let albumChangeRequest = PHAssetCollectionChangeRequest(for: album)
        albumChangeRequest?.addAssets([_placeholder] as NSFastEnumeration)
    }) { success, error in
        completion(nil)
    }
}

Моя проблема в том, что изображения/видео дублируются во всех фотографиях/фотопленке.

Я также нашел несколько сообщений об этом, например:

Перемещение/копирование PHAsset из одного альбома в другой

Но мне это не помогло.


person Dharmesh Kheni    schedule 29.06.2021    source источник


Ответы (1)


Вы запрашиваете исходные файлы здесь -

// Video
PHCachingImageManager().requestAVAsset(forVideo: asset, options: videoOptions) { (playerItem, audioMix, args) in

// Image
PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options, resultHandler: { (data, string, orientation, any) in

а затем создайте здесь новый/дублирующий актив -

let assetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let placeholder = assetRequest.placeholderForCreatedAsset

Мы не заинтересованы в создании нового PHAsset — мы связываем существующий PHAsset с альбомом. То, что вам нужно сделать, так же просто, как -

PHPhotoLibrary.shared().performChanges({
    let albumUpdateRequest = PHAssetCollectionChangeRequest(for: album) // album you plan to update
    albumUpdateRequest?.addAssets(NSArray(array: [asset])) // asset you plan to add
}, completionHandler: { (completed, error) in
    print("completed: \(completed), error: \(String(describing: error))")
})
person Tarun Tyagi    schedule 29.06.2021
comment
Это сработало!! но с небольшим изменением. Я заменил NSArray(array: [asset]) на assets as NSFastEnumeration. Спасибо за вашу помощь. - person Dharmesh Kheni; 29.06.2021