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
There are a couple of issues:
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 { ... }
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
.
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.
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.
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
You should use if let to unwrap your optionals. Also NSData.dataWithContentsOfMappedFile
was deprecated iOS8. Try using NSData method initializer contentsOfURL:
Note: You need also to change the didFinishPickingMediaWithInfo declaration from [NSObject : AnyObject]
to [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)
}
}
}
as mentioned by Rob the data can be really large but instead of copying the file you should move the file to the documents folder as follow:
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)
}
}