【问题标题】:Swift Write Video NSData to GallerySwift 将视频 NSData 写入图库
【发布时间】:2026-02-13 03:05:04
【问题描述】:

我正在 swift 上编写一个 iOS 应用程序,它从 URL 下载视频并将其写入磁盘。我正在获取数据,但迄今为止未能成功写入磁盘。下面是代码:

let yourURL = NSURL(string: "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_10mb.mp4")
    //Create a URL request
    let urlRequest = NSURLRequest(URL: yourURL!)
    //get the data
    var theData = NSData();
    do{
        theData = try NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse: nil)
    }
    catch let err as NSError
    {

    }

    try! PHPhotoLibrary.sharedPhotoLibrary().performChangesAndWait({ ()-> Void in
        if #available(iOS 9.0, *) {
            PHAssetCreationRequest.creationRequestForAsset().addResourceWithType(PHAssetResourceType.Video, data: theData, options: nil)

            print("SUCESS");
        } else {

        };

    });

我收到以下错误,感谢任何见解:

fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=-1 "(null)": file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-703.0.18.1/src/swift/stdlib/public/core/ErrorType.swift, line 54

【问题讨论】:

  • 不要使用try!,而是使用do-try-catch 模式并打印生成的error 对象。它可能会给你一个更有意义的错误信息。
  • 我在尝试时遇到类似的错误:Error Domain=NSCocoaErrorDomain Code=-1 "(null)"
  • 我是 iOS 编程新手,所以我仍在学习中。对不起,您指的是localizedDescription 和userInfo 是什么?是的,该应用已请求并有权访问照片库。
  • 当我打印出本地化描述时,我收到以下消息:“操作无法完成。(Cocoa 错误 -1。)”
  • 是的,当我设置断点检查时,数据不为零。

标签: ios objective-c iphone swift xcode


【解决方案1】:

一个问题是您试图将视频(可能非常大)加载到NSData 的内存中。如果您可以流式传输到持久存储中的文件,或者从这些文件流式传输,那就更好了。您可以通过使用NSURLSession 下载任务而不是使用已弃用的NSURLConnection 方法sendSynchronousRequest 来完成此操作。

通过使用NSURLSession 下载任务,您可以避免一次尝试将大型视频保存在内存中,而是将视频直接流式传输到持久存储。 (注意,不要使用NSURLSession 数据任务,因为这将与NSURLConnection 的已弃用方法sendSynchronousRequest 具有相同的内存占用问题。)

NSURLSession 下载任务将下载直接流式传输到持久存储后,您可以将文件移动到临时文件,然后使用 addResourceWithType,再次提供文件 URL 而不是 NSData

当我这样做时(并添加了一些其他有用的错误检查),它似乎工作正常:

// make sure it's authorized

PHPhotoLibrary.requestAuthorization { authorizationStatus in
    guard authorizationStatus == .Authorized else {
        print("cannot proceed without permission")
        return
    }

    self.downloadVideo()
}

地点:

func downloadVideo() {
    let fileManager = NSFileManager.defaultManager()

    // create request

    let url = NSURL(string: "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_10mb.mp4")!
    let task = NSURLSession.sharedSession().downloadTaskWithURL(url) { location, response, error in
        // make sure there weren't any fundamental networking errors

        guard location != nil && error == nil else {
            print(error)
            return
        }

        // make sure there weren't and web server errors

        guard let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200 else {
            print(response)
            return
        }

        // move the file to temporary folder

        let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
            .URLByAppendingPathComponent(url.lastPathComponent!)

        do {
            try fileManager.moveItemAtURL(location!, toURL: fileURL)
        } catch {
            print(error)
            return
        }

        // now save it in our photo library

        PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            PHAssetCreationRequest.creationRequestForAsset().addResourceWithType(.Video, fileURL: fileURL, options: nil)
        }, completionHandler: { success, error in
            defer {
                do {
                    try fileManager.removeItemAtURL(fileURL)
                } catch let removeError {
                    print(removeError)
                }
            }

            guard success && error == nil else {
                print(error)
                return
            }

            print("SUCCESS")
        })
    }
    task.resume()
}

注意,因为NSURLSession 更严格地确保您不执行不安全的请求,您可能需要更新info.plist(右键单击它并选择“打开方式”-“源代码”)并将此添加到文件中:

<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>sample-videos.com</key>
        <dict>
            <!--Include to allow subdomains-->
            <key>NSIncludesSubdomains</key>
            <true/>
            <!--Include to allow HTTP requests-->
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <!--Include to specify minimum TLS version-->
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
        </dict>
    </dict>
</dict>

但是,当我完成所有这些操作时,视频已成功下载并添加到我的照片库中。请注意,我在这里删除了所有同步请求(NSURLSession 是异步的,performChanges 也是如此),因为您几乎不想执行同步请求(当然也永远不会在主队列上)。

【讨论】: