How to convert video (in gallery) to NSData? in Swift

后端 未结 2 1418
礼貌的吻别
礼貌的吻别 2020-12-06 20:56

I just haven\'t \"info\" in Swift imagePickerController so I don\'t know how get url and convert it to data to send to web-service.

func imagePickerControll         


        
2条回答
  •  自闭症患者
    2020-12-06 21:18

    There are a couple of issues:

    1. Consider this line:

      var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
      

      This does a forced unwrapping of info[UIImagePickerControllerMediaURL] (which is bad, because if it was nil, the app would crash) and that casts it as an implicitly unwrapped optional NSURL!. That doesn't make sense. Just do a conditional unwrapping (and unwrap to a NSURL, not a NSURL!):

      if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
      
    2. The next line calls filePathURL:

      var videoFileURL = videoDataURL.filePathURL
      

      If you wanted a file URL, you already have one, so no conversion is needed, but instead just use videoDataURL. If you really wanted a path, you'd use path method:

      let videoPath = videoDataURL.path
      

      Frankly, Apple is trying to shift us away from using string paths, so just use the original videoDataURL and avoid the use of both path and filePathURL.

    3. You are using dataWithContentsOfMappedFile:

      var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
      

      If you really wanted to use dataWithContentsOfMappedFile, the proper Swift syntax is:

      let video = NSData(contentsOfMappedFile: videoPath!)
      

      But dataWithContentsOfMappedFile deprecated, so you should instead use:

      let video = try NSData(contentsOfFile: videoPath!, options: .DataReadingMappedIfSafe)
      

      Or, bypassing that videoPath altogether, you could:

      let video3 = try NSData(contentsOfURL: videoDataURL, options: .DataReadingMappedIfSafe)
      

      Obviously, those try renditions should be done within a do block with a catch block.

    4. By the way, as you'll see in all of my above examples, one should use let where possible.

    --

    Quite frankly, I would advise against loading it into a NSData at all. Just copy it with NSFileManager, which is a more efficient use of memory. If the video is long, it could be quite large, and you should avoid loading the whole thing into memory at any given point in time.

    So you could:

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

    If you're uploading this to a web service, you'd then use a NSURLSessionUploadTask, using file or stream options. The construction of this request is a separate question, but hopefully you get the idea: With large assets like photos or, especially, videos, don't instantiate a NSData with the asset if you can possibly avoid it.

提交回复
热议问题