PHPhotoLibrary 复制图像和视频时执行更改错误

问题描述 投票:0回答:3

用户可以从服务器下载图像和视频文件,然后将其临时存储在应用程序的文档路径下,然后使用

PHAssetChangeRequest.creationRequestForAssetFromImage
PHAssetChangeRequest.creationRequestForAssetFromVideo
从那里复制到iOS照片库中的自定义相册。

当仅下载图像文件或视频文件时,此功能完美无缺,但当图像和视频混合在同一个下载批次中时,总会有一些文件因以下错误之一而任意失败:

错误是:操作无法完成。 (PHPhotosErrorDomain 错误 -1。)

错误是:操作无法完成。 (PHPhotosErrorDomain 错误 3302。)

这是将文件复制到照片库的负责代码:

public func saveFileToPhotoLibrary(_ url: URL, completion: @escaping (Bool) -> Void)
{
    guard let album = _album else
    {
        completion(false)
        return
    }

    guard let supertype = url.supertype else
    {
        completion(false)
        return
    }

    if supertype == .image || supertype == .movie
    {
        DispatchQueue.global(qos: .background).async
        {
            PHPhotoLibrary.shared().performChanges(
            {
                guard let assetChangeRequest = supertype == .image
                    ? PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: url)
                    : PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url) else
                {
                    completion(false)
                    return
                }

                guard let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset else
                {
                    completion(false)
                    return
                }

                guard let albumChangeRequest = PHAssetCollectionChangeRequest(for: album) else
                {
                    completion(false)
                    return
                }

                albumChangeRequest.addAssets([assetPlaceholder] as NSFastEnumeration)
            })
            {
                saved, error in

                if let error = error
                {
                    print("Failed to save image file from \(url.lastPathComponent) to photo gallery. Error was: \(error.localizedDescription)")
                    DispatchQueue.main.async { completion(false) }
                }
            }
        }
    }
}

有谁知道为什么会发生错误或如何解决此问题以免文件副本失败?

ios swift file photo-gallery
3个回答
0
投票

解决了!上面的代码按预期工作。问题在于,由于服务器提供的文件顺序和文件名,某些视频和图像文件之间的文件类型混淆了。因此,有时视频可能会收到图像文件类型扩展名,反之亦然。这似乎混淆了 PHPhotoLibrary 创建RequestForAssetFromImage API。


0
投票

PHPhotosErrorDomain error 3302
表示
invalidResource
,请参阅错误代码列表。这发生在我身上,因为我试图从临时目录中的文件中保存图片。似乎只能使用特定目录:

// FAILS
let imageUrl = FileManager.default.temporaryDirectory.appendingPathComponent("save-me")

// WORKS
let documentsPath = NSSearchPathForDirectoriesInDomains(
  .documentDirectory, .userDomainMask, true)[0]
let filePath = "\(documentsPath)/tempFile.jpg"
let imageUrl = URL(fileURLWithPath: filePath)

// And then
PHPhotoLibrary.shared().performChanges(
  {
    let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(
      atFileURL: imageUrl)

    [...]

您还可能会收到其他神秘错误。例如,

3300
表示
changeNotSupported
,如果您尝试将资产添加到特殊相册(例如“Recents”)(标识为
PHAssetCollectionType.smartAlbum
+
PHAssetCollectionSubtype.smartAlbumUserLibrary
),则可能会出现此情况。


0
投票

我也遇到了同样的错误,当我们下载并创建扩展名(MemeType)时,应该是一个正确的例子,如果我们想保存 mp4 文件,我们应该下载 .mp4 文件,如果任何原因不匹配,那么我们将面临这个类型错误。当您不确切知道文件类型时,我会安排代码片段来实现它。

  enum FileType {
    case jpg
    case mp4
    case ogv
    case webm
    case threeGP
    case unknown 
 } 


func determineFileType(data: Data) -> FileType {
var values = [UInt8](repeating:0, count:4)
data.copyBytes(to: &values, count: 4)

if values[0] == 0xFF && values[1] == 0xD8 && values[2] == 0xFF {
    return .jpg
} else if values[0] == 0x00 && values[1] == 0x00 && values[2] == 0x00 {
    return .mp4 // Basic heuristic for .mp4
} else if values[0] == 0x4F && values[1] == 0x67 && values[2] == 0x67 && values[3] == 0x53 {
    return .ogv
} else if values[0] == 0x1A && values[1] == 0x45 && values[2] == 0xDF && values[3] == 0xA3 {
    return .webm
} else if values[0] == 0x66 && values[1] == 0x74 && values[2] == 0x79 && values[3] == 0x70 {
    return .threeGP // Basic heuristic for .3gp
} else {
    return .unknown
}}

private func saveDataAsVideoFile(_ data: Data, completion: @escaping (Bool, Error?) -> Void) {
let fileType = determineFileType(data: data)
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath: String

switch fileType {
case .jpg:
    filePath = "\(documentsPath)/tempFile.jpg"
case .mp4:
    filePath = "\(documentsPath)/tempFile.mp4"
case .ogv:
    filePath = "\(documentsPath)/tempFile.ogv"
case .webm:
    filePath = "\(documentsPath)/tempFile.webm"
case .threeGP:
    filePath = "\(documentsPath)/tempFile.3gp"
case .unknown:
    completion(false, nil)
    return
}

let fileUrl = URL(fileURLWithPath: filePath)

do {
    try data.write(to: fileUrl)
    
    PHPhotoLibrary.shared().performChanges({
        // Since PHAssetChangeRequest doesn't support other video formats like .ogv, .webm or .3gp directly,
        // you might be limited in the types of videos you can save to the Photos library.
        if fileType == .jpg {
            _ = PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: fileUrl)
        } else if fileType == .mp4 || fileType == .threeGP {
            _ = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: fileUrl)
        } else {
            completion(false, nil)
            return
        }
    }) { success, error in
        completion(success, error)
    }
    
} catch {
    print("Error saving data: \(error)")
    completion(false, error)
} }
© www.soinside.com 2019 - 2024. All rights reserved.