【问题标题】:How to convert video (in gallery) to NSData? in Swift如何将视频(在图库中)转换为 NSData?在斯威夫特
【发布时间】:2016-01-16 07:12:49
【问题描述】:

我只是在 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)")
}

【问题讨论】:

  • 请澄清您的问题。您发布的代码中的“info”参数有什么问题?
  • 酷发布的代码在 Swift 中工作而不是 swift2 我问它是如何在 swift 中工作的 2 这个我的函数参数中没有信息“ func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?)"
  • 发布的代码在什么情况下不能在 Swift 2 中工作?您评论中的委托方法已弃用。使用您问题中的那个。只需将info 参数修改为[String : AnyObject]
  • 谢谢我错了它可以工作

标签: ios swift swift3


【解决方案1】:

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)
        }
    }
}

斯威夫特 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)
    }
}

【讨论】:

    【解决方案2】:

    有几个问题:

    1. 考虑这一行:

      var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
      

      这会强制解包info[UIImagePickerControllerMediaURL](这很糟糕,因为如果是nil,应用程序会崩溃)并将其转换为隐式解包的可选NSURL!。那没有意义。只需进行有条件的展开(并展开为NSURL,而不是NSURL!):

      if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
      
    2. 下一行调用filePathURL

      var videoFileURL = videoDataURL.filePathURL
      

      如果您想要一个文件 URL,您已经有了一个,因此无需转换,只需使用 videoDataURL。如果你真的想要一条路径,你会使用path 方法:

      let videoPath = videoDataURL.path
      

      坦率地说,Apple 正试图让我们不再使用字符串路径,所以只需使用原始的 videoDataURL 并避免同时使用 pathfilePathURL

    3. 你正在使用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 块内完成。

    4. 顺便说一句,正如您将在我上面的所有示例中看到的那样,应该尽可能使用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

    【讨论】:

    • 您还应该解释这个答案如何解决问题中的问题。
    • @rmaddy - 我正在斩钉截铁,但我修改了答案来描述问题。
    • 嗨,罗伯!有什么方法可以读取范围内的数据并上传到服务器。示例:假设我有一个 1 Gb 的视频,那么首先我读取 0 - 50 MB 并上传到服务器,然后读取 50 - 100 Mb 并上传等等。
    • @FarooqueAzam - 因为您仍在处理大型上传(每个 50MB),我倾向于为每个 50MB 块创建单独的文件。例如。创建InputStream 并开始读取内容(可能一次读取10-100kb),写入您为每个50MB 块创建的OutputStream。然后,您可以对这些单个文件进行基于文件的上传(非常适合背景URLSession)。但这超出了这个问题的范围,所以如果您真的有其他问题,请在 Stack Overflow 上创建您自己的问题。
    【解决方案3】:

    选择视频后,此方法将被调用

    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)
            }
            
            }
       
    }
    

    【讨论】:

      【解决方案4】:

      找到简单的解决方案:

      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)
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2015-06-07
        • 1970-01-01
        • 2017-02-02
        • 2015-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多