如何将视频(在图库中)转换为 NSData?在 Swift
How to convert video (in gallery) to NSData? in Swift
我只是 "info" Swift imagePickerController 中没有,所以我不知道如何获取 url 并将其转换为数据以发送到网络服务。
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
var videoFileURL = videoDataURL.filePathURL
var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
}
Xcode 10 • Swift 4.2 或更高版本
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
if let url = info[.mediaURL] as? URL {
do {
try FileManager.default.moveItem(at: url, to: documentsDirectoryURL.appendingPathComponent("videoName.mov"))
print("movie saved")
} catch {
print(error)
}
}
}
Xcode 8.3 • Swift 3.1
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
if let fileURL = info[UIImagePickerControllerMediaURL] as? URL {
do {
try FileManager.default.moveItem(at: fileURL, to: documentsDirectoryURL.appendingPathComponent("videoName.mov")
print("movie saved")
} catch {
print(error)
}
}
}
Swift 2
你应该使用 if let 来解包你的可选值。 NSData.dataWithContentsOfMappedFile
也被弃用 iOS8。尝试使用 NSData 方法初始值设定项 contentsOfURL:
注意:您还需要将 didFinishPickingMediaWithInfo 声明从 [NSObject : AnyObject]
更改为 [String : AnyObject]
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let fileURL = info[UIImagePickerControllerMediaURL] as? NSURL {
if let videoData = NSData(contentsOfURL: fileURL) {
print(videoData.length)
}
}
}
如 Rob 所述,数据可能非常大,但您不应复制文件,而是应将文件移动到文档文件夹,如下所示:
let documentsDirectoryURL = try! NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if let fileURL = info[UIImagePickerControllerMediaURL] as? NSURL {
do {
try NSFileManagerdefaultManager().moveItemAtURL(fileURL, toURL: documentsDirectoryURL.URLByAppendingPathComponent("videoName").URLByAppendingPathExtension("mov"))
print("movie saved")
} catch {
print(error)
}
}
有几个问题:
考虑这一行:
var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
这会强制解包 info[UIImagePickerControllerMediaURL]
(这很糟糕,因为如果它是 nil
,应用程序会崩溃)并将其转换为隐式解包的可选 NSURL!
.那没有意义。只需进行有条件的解包(并解包为 NSURL
,而不是 NSURL!
):
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
下一行调用filePathURL
:
var videoFileURL = videoDataURL.filePathURL
如果您想要一个文件 URL,您已经有了一个,因此无需转换,只需使用 videoDataURL
。如果你真的想要一个路径,你会使用 path
方法:
let videoPath = videoDataURL.path
坦率地说,Apple 正试图让我们不再使用字符串路径,因此只需使用原始的 videoDataURL
并避免同时使用 path
和 filePathURL
。
您正在使用 dataWithContentsOfMappedFile
:
var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
如果您真的想使用 dataWithContentsOfMappedFile
,正确的 Swift 语法是:
let video = NSData(contentsOfMappedFile: videoPath!)
但 dataWithContentsOfMappedFile
已弃用,因此您应该改用:
let video = try NSData(contentsOfFile: videoPath!, options: .DataReadingMappedIfSafe)
或者,完全绕过 videoPath
,您可以:
let video3 = try NSData(contentsOfURL: videoDataURL, options: .DataReadingMappedIfSafe)
显然,那些 try
演绎版应该在带有 catch
块的 do
块中完成。
顺便说一下,正如您将在我上面的所有示例中看到的那样,应该尽可能使用 let
。
--
坦率地说,我建议不要将它加载到 NSData
中。用NSFileManager
复制就可以了,内存使用效率更高。如果视频很长,它可能会很大,您应该避免在任何给定时间点将整个视频加载到内存中。
所以你可以:
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL {
do {
// build your destination URL however you want
//
// let tempFolder = NSURL(fileURLWithPath: NSTemporaryDirectory())
// let destinationURL = tempFolder.URLByAppendingPathComponent("test.mov")
// or
let documents = try NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let destinationURL = documents.URLByAppendingPathComponent("test.mov")
// but just copy from the video URL to the destination URL
try NSFileManager.defaultManager().copyItemAtURL(videoDataURL, toURL: destinationURL)
} catch {
print(error)
}
}
如果您要将其上传到网络服务,则可以使用 NSURLSessionUploadTask
,使用文件或流选项。这个请求的构造是一个单独的问题,但希望你能理解:对于像照片或视频这样的大型资产,如果可以避免的话,不要用资产实例化 NSData
。
选择视频后将调用此方法
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
print("in here")
if let pickedVideo = info[UIImagePickerController.InfoKey(rawValue: UIImagePickerController.InfoKey.mediaURL.rawValue)] as? URL {
print(pickedVideo)
do {
print("Converted")
// let VideoData = try Data(contentsOf: pickedVideo)
uploadVideo(VideoData: try Data(contentsOf: pickedVideo), URL: pickedVideo)
} catch let error {
print(error.localizedDescription)
}
}
}
找到简单的解决方案:
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.dismiss(animated: true, completion: nil)
// Using just the information key value
if let url = info[.mediaURL] as? URL {
// Do something with the URL
print("Media URL : ",url)
do {
let videoData = try Data(contentsOf: url)
}
catch let error {
print(error)
}
}
}
我只是 "info" Swift imagePickerController 中没有,所以我不知道如何获取 url 并将其转换为数据以发送到网络服务。
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
var videoFileURL = videoDataURL.filePathURL
var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
}
Xcode 10 • Swift 4.2 或更高版本
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
if let url = info[.mediaURL] as? URL {
do {
try FileManager.default.moveItem(at: url, to: documentsDirectoryURL.appendingPathComponent("videoName.mov"))
print("movie saved")
} catch {
print(error)
}
}
}
Xcode 8.3 • Swift 3.1
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
if let fileURL = info[UIImagePickerControllerMediaURL] as? URL {
do {
try FileManager.default.moveItem(at: fileURL, to: documentsDirectoryURL.appendingPathComponent("videoName.mov")
print("movie saved")
} catch {
print(error)
}
}
}
Swift 2
你应该使用 if let 来解包你的可选值。 NSData.dataWithContentsOfMappedFile
也被弃用 iOS8。尝试使用 NSData 方法初始值设定项 contentsOfURL:
注意:您还需要将 didFinishPickingMediaWithInfo 声明从 [NSObject : AnyObject]
更改为 [String : AnyObject]
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let fileURL = info[UIImagePickerControllerMediaURL] as? NSURL {
if let videoData = NSData(contentsOfURL: fileURL) {
print(videoData.length)
}
}
}
如 Rob 所述,数据可能非常大,但您不应复制文件,而是应将文件移动到文档文件夹,如下所示:
let documentsDirectoryURL = try! NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if let fileURL = info[UIImagePickerControllerMediaURL] as? NSURL {
do {
try NSFileManagerdefaultManager().moveItemAtURL(fileURL, toURL: documentsDirectoryURL.URLByAppendingPathComponent("videoName").URLByAppendingPathExtension("mov"))
print("movie saved")
} catch {
print(error)
}
}
有几个问题:
考虑这一行:
var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
这会强制解包
info[UIImagePickerControllerMediaURL]
(这很糟糕,因为如果它是nil
,应用程序会崩溃)并将其转换为隐式解包的可选NSURL!
.那没有意义。只需进行有条件的解包(并解包为NSURL
,而不是NSURL!
):if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
下一行调用
filePathURL
:var videoFileURL = videoDataURL.filePathURL
如果您想要一个文件 URL,您已经有了一个,因此无需转换,只需使用
videoDataURL
。如果你真的想要一个路径,你会使用path
方法:let videoPath = videoDataURL.path
坦率地说,Apple 正试图让我们不再使用字符串路径,因此只需使用原始的
videoDataURL
并避免同时使用path
和filePathURL
。您正在使用
dataWithContentsOfMappedFile
:var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
如果您真的想使用
dataWithContentsOfMappedFile
,正确的 Swift 语法是:let video = NSData(contentsOfMappedFile: videoPath!)
但
dataWithContentsOfMappedFile
已弃用,因此您应该改用:let video = try NSData(contentsOfFile: videoPath!, options: .DataReadingMappedIfSafe)
或者,完全绕过
videoPath
,您可以:let video3 = try NSData(contentsOfURL: videoDataURL, options: .DataReadingMappedIfSafe)
显然,那些
try
演绎版应该在带有catch
块的do
块中完成。顺便说一下,正如您将在我上面的所有示例中看到的那样,应该尽可能使用
let
。
--
坦率地说,我建议不要将它加载到 NSData
中。用NSFileManager
复制就可以了,内存使用效率更高。如果视频很长,它可能会很大,您应该避免在任何给定时间点将整个视频加载到内存中。
所以你可以:
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL {
do {
// build your destination URL however you want
//
// let tempFolder = NSURL(fileURLWithPath: NSTemporaryDirectory())
// let destinationURL = tempFolder.URLByAppendingPathComponent("test.mov")
// or
let documents = try NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let destinationURL = documents.URLByAppendingPathComponent("test.mov")
// but just copy from the video URL to the destination URL
try NSFileManager.defaultManager().copyItemAtURL(videoDataURL, toURL: destinationURL)
} catch {
print(error)
}
}
如果您要将其上传到网络服务,则可以使用 NSURLSessionUploadTask
,使用文件或流选项。这个请求的构造是一个单独的问题,但希望你能理解:对于像照片或视频这样的大型资产,如果可以避免的话,不要用资产实例化 NSData
。
选择视频后将调用此方法
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
print("in here")
if let pickedVideo = info[UIImagePickerController.InfoKey(rawValue: UIImagePickerController.InfoKey.mediaURL.rawValue)] as? URL {
print(pickedVideo)
do {
print("Converted")
// let VideoData = try Data(contentsOf: pickedVideo)
uploadVideo(VideoData: try Data(contentsOf: pickedVideo), URL: pickedVideo)
} catch let error {
print(error.localizedDescription)
}
}
}
找到简单的解决方案:
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.dismiss(animated: true, completion: nil)
// Using just the information key value
if let url = info[.mediaURL] as? URL {
// Do something with the URL
print("Media URL : ",url)
do {
let videoData = try Data(contentsOf: url)
}
catch let error {
print(error)
}
}
}