Reputation: 767
Working in Swift 3. I found numerous questions with answers and then also blogs, yet everything I've tried didn't work. I am just trying to capture a camera shot I take and save it to the documents. But it isn't being saved as it doesn't show up under devices documents when viewed from within xcode and I don't get any errors or similar. I'm at a bit of a lost here.
Code that have for getting the image and saving it
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var pickedImage = UIImage()
pickedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
picker.dismiss(animated: true, completion: nil)
let currentDateTime = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMddHHmmss"
let fileNameWithExtension = "ts_\(formatter.string(from: currentDateTime)).png"
//create path
let imagePath = fileInDocumentsDirectory(filename: fileNameWithExtension)
imageStringPathSet = fileNameWithExtension
imageSet = pickedImage
if saveImage(image: pickedImage, path: imagePath) {
cameraButton.setImage(#imageLiteral(resourceName: "ic_camerashot_yes60dp"), for: UIControlState.normal)
return
}
cameraButton.setImage(#imageLiteral(resourceName: "ic_camerashot_no60dp"), for: UIControlState.normal)
}
func fileInDocumentsDirectory(filename: String)-> URL {
return try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(filename)
}
func saveImage(image: UIImage, path: URL) -> Bool {
print(path)
guard let pngImageData = UIImagePNGRepresentation(image) else {
print("error")
return false
}
var resultValid = false
do {
let results = try pngImageData.write(to: path, options: [.atomicWrite])
print(results) //prints ()
resultValid = true
}
catch {
resultValid = false
print(error)
}
return resultValid
}
When I print the path it prints
file:///var/mobile/Containers/Data/Application/01EB6A70-34C6-4481-BE5B-7F7AB5E6703F/Documents/ts_20161221145652.png
Which I believe is correct. If everything works correctly, it changes an image on the screen yet it never changes and the imageStringPathSet isn't set either which is a class variable. Anyone have any ideas on what I need to do to get this to work?
Solution
Turns out the cause was that I was resetting everything in the view in viewWillAppear. Once I fixed this, things worked fine. Thanks everyone for your feedback. Hope this helps someone else to not do what I did.
Upvotes: 0
Views: 2377
Reputation:
As per the request in the comments, here's my code that (a) uses the UIImagePickerController to either select from the camera roll, then (b) uses the UIActivityViewController to let the user choose among several possible ways to save/attach the image to several sources of output.
While this isn't saving to the document directory, it may be a better route to go. Please pay attention to a few notes after the code listing.
My "select" view controller, which allows a user to either pick from the camera roll or take a picture:
extension SelectViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// MARK: Camera App
func openCameraApp() {
if UIImagePickerController.availableCaptureModes(for: .rear) != nil {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker,
animated: true,
completion: nil)
} else {
noCamera()
}
}
func noCamera(){
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .alert)
let okAction = UIAlertAction(
title: "OK",
style:.default,
handler: nil)
alertVC.addAction(okAction)
present(
alertVC,
animated: true,
completion: nil)
}
// MARK: Photos Albums
func showImagePicker() {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
// picker.modalPresentationStyle = .Popover
present(picker,
animated: true,
completion: nil)
picker.popoverPresentationController?.sourceView = self.view
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
image = chosenImage
self.performSegue(withIdentifier: "ShowEditView", sender: self)
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: false, completion: nil)
}
// MARK: Seque to EditViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEditView" {
if let vc = segue.destination as? EditViewController {
vc.image = image
}
}
}
}
My "edit" view controller, which is embedded in a UINavigationBar with a button on it set to System Item == Action:
// MARK: Image actions
@IBAction func shareImage(_ sender: UIBarButtonItem) {
let context = CIContext()
let final = context.createCGImage(imgEdited, from: imgEdited.extent)
let shareImage = UIImage(cgImage: final!)
let vc = UIActivityViewController(activityItems: [shareImage], applicationActivities: [])
vc.excludedActivityTypes = [
//UIActivityTypePostToTwitter,
//UIActivityTypePostToFacebook,
UIActivityType.postToWeibo,
//UIActivityTypeMessage,
//UIActivityTypeMail,
UIActivityType.print,
//UIActivityTypeCopyToPasteboard,
UIActivityType.assignToContact,
//UIActivityTypeSaveToCameraRoll,
UIActivityType.addToReadingList,
//UIActivityTypePostToFlickr,
UIActivityType.postToVimeo,
UIActivityType.postToTencentWeibo
]
present(vc,
animated: true,
completion: nil)
vc.popoverPresentationController?.sourceView = self.view
vc.completionWithItemsHandler = {(activity, success, items, error) in
}
}
Notes:
Keep in mind that when using the UIImagePickerController in an iOS 10 device, it will crash unless you add this to your info.plist:
<key>NSCameraUsageDescription</key>
<string>Used to capture new image for photo effect</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to select an image for photo effect</string>
You may use whatever you wish in the tag.
The UIActivityViewController will present all commented out options in it's excludedActivityTypes. (I keep these options listed just for self documentation.) If a user has Facebook and wants to post to it, they'll be prompted to login if they aren't yet.
Upvotes: 1