Iam using PHPickerViewController to load multiple images and store them to CoreData.
Along with the imagepicker, there are three more parameters, which are successfully passed from a previous tableview on tapping its cell.
In coredata i have created an additional parameter galleryImage, of type NSObject to pass this images as array
//button tap to select picker
#IBAction func gallerySelectClicked(_ sender: Any) {
presentPickerView()
}
//configure
func presentPickerView() {
var config : PHPickerConfiguration = PHPickerConfiguration()
config.selectionLimit = 10
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = self
self.present(pickerViewController, animated: true, completion: nil)
}
//Saving
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
for item in results {
item.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { (image, err) in
if let image = image as? UIImage {
print(image)
DispatchQueue.main.async {
self.Gallery.image = image
let dh = DatabaseHandler()
//Databasehandler in another file
dh.imgArray.append(image)
dh.saveImage()
}
}
})
}
}
Saveimage function in Databasehandler
func saveImage() {
let appDe = (UIApplication.shared.delegate) as! AppDelegate
let context = appDe.persistentContainer.viewContext
let photo = NSEntityDescription.insertNewObject(forEntityName: "People", into: context) as! People
var CDataArray = NSMutableArray();
for img in imgArray{
let data : NSData = NSData(data: img.jpegData(compressionQuality: 1)!)
CDataArray.add(data);
}
photo.galleryImage = NSKeyedArchiver.archivedData(withRootObject: CDataArray) as NSObject;
do{
try context.save()
print("data saved" )
} catch{
print("error")
}
}
Problem is when I select 2 images and print count to check wheather it is saved, output will be 2. when I select another 2 images in a second run, output is 4 . In this way, count keeos increasing
Could you please help me to find whats wrong with this code? I couldnt find any other good reference for PHPickerController .
Related
I would like to be able to select a photo from the Photos library using UIImagePicker and copy all the image (with modified Exif metadata) to a new photo which I save in Photos. If I use UIActivityViewController to choose the save option (from copy/save/assign to contact/print/add to shared album/save to file), the input image metadata is not transferred when I create a new UIimage from the loaded image data with the modified metadata. How can get the image with modified metadata attached to the saved photo?
Eventually found out how to do this. The code executed after the image picker is below. The important thing is to create the source from which the metadata is extracted from a URL, not from data from image.jpegData. The jpegData option only includes metadata essential to JPEG operation
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
if let image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)] as? UIImage {
let url = info[UIImagePickerController.InfoKey.imageURL.rawValue]
let source = CGImageSourceCreateWithURL(url as! CFURL, nil)
let metadata = CGImageSourceCopyPropertiesAtIndex(source!,0,nil) as? [AnyHashable: Any]
var metadataAsMutable = metadata
//let ImagePropertyExifDictionary = kCGImagePropertyExifDictionary
guard var exif = metadataAsMutable![kCGImagePropertyExifDictionary] as? [String:Any] else {return}
if((exif[kCGImagePropertyExifUserComment as String] == nil))
{
exif[kCGImagePropertyExifUserComment as String] = "Test User Comment"
}
metadataAsMutable![kCGImagePropertyExifDictionary] = exif as CFDictionary
ImagePickerView.contentMode = .scaleAspectFit
let image2 = image.imageWithInsets(insets: UIEdgeInsets.init(top: 0,left: 0,bottom: 300,right: 0))
let data1 = image2!.jpegData(compressionQuality: 1.0)
newData = addImageProperties(imageData: data1!, properties: metadataAsMutable! as CFDictionary)
image3 = UIImage(data:newData)!
ImagePickerView.image = image3
captionButton.isEnabled = true; saveButton.isEnabled = true;
}else {
print("Error")
}
self.dismiss(animated: true, completion: nil)
}
func addImageProperties(imageData: Data, properties: NSMutableDictionary) -> Data? {
if let source = CGImageSourceCreateWithData(imageData as CFData, nil) {
if let uti = CGImageSourceGetType(source) {
let destinationData = NSMutableData()
if let destination = CGImageDestinationCreateWithData(destinationData, uti, 1, nil) {
CGImageDestinationAddImageFromSource(destination, source, 0, properties)
if CGImageDestinationFinalize(destination) == false {
return nil
}
return destinationData as Data
}
}
}
return nil
}
After obtaining newData, the save button IBAction is
#IBAction func shareAction(_ sender: Any) {
self.saveImageDataAsImage(newData)
}
and the function to save the image in the same album as the selected image is
func saveImageDataAsImage(_ data: Data) {
var newImageIdentifier: String!
PHPhotoLibrary.shared().performChanges{
//if #available(iOS 9.0, *) {
let assetRequest = PHAssetCreationRequest.forAsset()
assetRequest.addResource(with: .photo, data: data, options: nil)
newImageIdentifier = assetRequest.placeholderForCreatedAsset!.localIdentifier
// } else {
// // Fallback on earlier versions
// }
} completionHandler: { (success, error) in
DispatchQueue.main.async(execute: {
if success, let newAsset = PHAsset.fetchAssets(withLocalIdentifiers: [newImageIdentifier], options: nil).firstObject {
// ...
} else {
// ...
}
})
}
}
I'm trying to upload a video to Google's Cloud Storage, but hit an error:
BackgroundSession <1EE0DA45-0AA5-45FB-AAB4-1580A53F88A8> error requesting a NSURLSessionUploadTask from background transfer daemon: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service on pid 27172 named com.apple.nsurlsessiond was interrupted, but the message was sent over an additional proxy and therefore this proxy has become invalid."
_NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <26C123A0-427F-45B9-B7A3-64AEBD19A2AA>.<1>, NSLocalizedDescription=unknown error}
Optional("An unknown error occurred, please check the server response.")
2021-03-01 17:00:28.536123+0000 ForfeitV3.2[72747:1363373] BackgroundSession <1EE0DA45-0AA5-45FB-AAB4-1580A53F88A8> connection to background transfer daemon invalidated
Here's my relevant Swift code:
func timelapsePopup() {
let imagePC = UIImagePickerController()
imagePC.sourceType = .photoLibrary
imagePC.delegate = self
imagePC.sourceType = .savedPhotosAlbum
imagePC.mediaTypes = [String(kUTTypeMovie)]
imagePC.allowsEditing = false
V.timelapse = true
present(imagePC, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if V.timelapse == true { //TIMELAPSE
V.timelapse = false
if let selectedVideo = info[UIImagePickerController.InfoKey.mediaURL] as? URL {
// fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
print("Here's the file URL: ", selectedVideo)
dismiss(animated: true, completion: nil)
brain.submitEvidence(itemIndex: V.indexToBePassed, image: UIImage(), timelapsePath: selectedVideo)
}
myTableView.reloadData()
}
mutating func submitEvidence(itemIndex: Int, image: UIImage, timelapsePath: URL) {
print(timelapsePath.absoluteString)
if timelapsePath.absoluteString != "" {
let item = V.items[itemIndex]
item.timelapseURL = timelapsePath
item.timeSubmitted = getCurrentTime()
item.sentForConfirmation = true
self.saveItem(item: item)
self.addTimelapseToFirestore(item: item)
} else {
let item = V.items[itemIndex]
item.image = image.toString()!
item.timeSubmitted = getCurrentTime()
item.sentForConfirmation = true
self.saveItem(item: item)
self.addToFirestore(item: item)
}
}
func addTimelapseToFirestore(item: Item) {
let storage = Storage.storage()
let data = Data()
let storageRef = storage.reference()
let localFile = item.timelapseURL
let photoRef = storageRef.child("videoOne")
let uploadTask = photoRef.putFile(from: localFile!, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
print(error?.localizedDescription)
return
}
print("video uploaded")
}
}
The weird thing is that it works when uploading an image. Ie if I change the kUTypeMovie to kUTypeImage, and a few other things to make images work, it uploads that just fine to Cloud Storage. When i switch it back to video, it fails.
All help greatly appreciated - let me know if there's any other info you need!
Cheers,
Josh
Please use the following code which uses UIImagePicker object class to select a video or image in your device and upload it to Firebase ( I have made some changes in your code):
#IBAction func uploadButton(_ sender: Any) {
// Configuration
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
picker.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]
// Present the UIImagePicker Controller
present(picker, animated: true, completion: nil)
}
// The didFinishPickingMediaWithInfo let's you select an image/video and let's you decide what to do with it.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if V.timelapse == true { //TIMELAPSE
V.timelapse = false
if let selectedVideo = info[UIImagePickerControllerMediaURL] as? NSURL {
// fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
print("Here's the file URL: ", selectedVideo)
dismiss(animated: true, completion: nil)
brain.submitEvidence(itemIndex: V.indexToBePassed, image: UIImage(), timelapsePath: selectedVideo)
}
myTableView.reloadData()
}
mutating func submitEvidence(itemIndex: Int, image: UIImage, timelapsePath: URL) {
print(timelapsePath.absoluteString)
if timelapsePath.absoluteString != "" {
let item = V.items[itemIndex]
item.timelapseURL = timelapsePath
item.timeSubmitted = getCurrentTime()
item.sentForConfirmation = true
self.saveItem(item: item)
self.addTimelapseToFirestore(item: item)
} else {
let item = V.items[itemIndex]
item.image = image.toString()!
item.timeSubmitted = getCurrentTime()
item.sentForConfirmation = true
self.saveItem(item: item)
self.addToFirestore(item: item)
}
}
func addTimelapseToFirestore(item: Item) {
let storage = Storage.storage()
let data = Data()
let storageRef = storage.reference()
let localFile = item.timelapseURL
let photoRef = storageRef.child("videoOne.mov")
let uploadTask = photoRef.putFile(from: localFile!, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
print(error?.localizedDescription)
return
}
print("video uploaded")
}
}
Please let me know if it works for you.
The code here allows me to upload and download one photo to Firebase and save it to user defaults but I'm trying to figure out how to do it within a collectionView cell and display as many photos wanted, adding on new items
import UIKit
import FirebaseStorage
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
private let storage = Storage.storage().reference()
#IBOutlet var imageView: UIImageView!
#IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
label.numberOfLines = 0
guard let urlString = UserDefaults.standard.value(forKey: "url") as? String, let url = URL(string: urlString) else {
return
}
label.text = urlString
let task = URLSession.shared.dataTask(with: url, completionHandler: { data,_,error in
guard let data = data, error == nil else {
return
}
DispatchQueue.main.async {
let image = UIImage(data: data)
self.imageView.image = image
}
})
task.resume()
}
#IBAction func didTapButton() {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
return
}
guard let imageData = image.pngData() else {
return
}
storage.child("Images/Photo.png").putData(imageData, metadata: nil) { (_, error) in
guard error == nil else {
print("Failed to Upload Data")
return
}
self.storage.child("Images/Photo.png").downloadURL(completion: {url, error in
guard let url = url, error == nil else {
return
}
let urlString = url.absoluteString
DispatchQueue.main.async {
self.label.text = urlString
self.imageView.image = image
}
print("Download URL: \(urlString)")
UserDefaults.standard.set(urlString, forKey: "url")
})
}
// Upload Image Data
// Get Download URL
// Save Download URL to userDefaults
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
To upload images to Firebase storage and show them in a collection view, you can use the following steps;
Set up collection view with an array of URLs (or Strings) as its
data source. You can use your custom models if required.
Keep a reference to your Firebase storage and upload the image. After successful upload, get the URL for the uploaded image using the image reference.
Save the url in Firebase Database(or Cloud Firestore). This is required only if you want to sync the collection view with the database and update it when new images are uploaded.
Add a listener to your Firebase database reference where you have
saved the image URLs. Update the local URLs array inside the listener and reload the collection view.
If you don't want to use Firebase database, omit steps 3 and 4, save the image URL to the array and reload the collection view right away.
I'm not adding the code for collection view setup here as it's not the objective of this answer.
let storageRef = Storage.storage().reference(withPath: "images")
let databaseRef = Database.database().reference(withPath:"images")
var images: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
addDatabaseListener()
}
private func addDatabaseListener() {
databaseRef.observe(.childAdded) { (snapshot) in
guard let value = snapshot.value as? [String: Any], let url = value["url"] as? String else { return }
self.images.append(url)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage, let data = image.jpegData(compressionQuality: 0.1) else { return }
let fileName = "\(Date.timeIntervalSinceReferenceDate).jpeg"
let newImageRef = storageRef.child(fileName)
newImageRef.putData(data, metadata: nil) { (_, error) in
if let error = error {
print("upload failed: ", error.localizedDescription)
return
}
newImageRef.downloadURL { (url, error) in
if let error = error {
print("error: ", error.localizedDescription)
return
}
self.databaseRef.childByAutoId().setValue(["url": url?.absoluteString])
}
}
}
So I have an edit profile page where the user can change their profile picture and cover photo. I have it to where once the users selects their image, they click the saveButton and the photo is uploaded to Firebase Database and Firebase Storage and then the edit profile viewcontroller is dismissed and returns to profile view. Only problem I am having is that although the photo uploads to firebase, it doesn't save the image on the app if I close out and reopen it. I'm not sure what I am missing to make that happen. Here is the code below:
import UIKit
import Foundation
import Firebase
import FirebaseDatabase
class NewEditProfileViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView1: UIImageView!
#IBOutlet weak var imageView2: UIImageView!
var ref = DatabaseReference.init()
var imagePicker = UIImagePickerController()
var imagePicked = 0
var selectedImage1: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
self.saveFIRData()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
}
#IBAction func chooseImage1(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
imagePicked = (sender as AnyObject).tag
present(imagePicker, animated: true)
}
}
#IBAction func chooseImage2(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
imagePicked = (sender as AnyObject).tag
present(imagePicker, animated: true)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let pickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
let pickedImage2 = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
if imagePicked == 1 {
self.imageView1.image = pickedImage
} else if imagePicked == 2 {
self.imageView2.image = pickedImage2
}
dismiss(animated: true)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true)
}
#IBAction func saveButton(_ sender: Any) {
self.saveFIRData()
self.dismiss(animated: true, completion: nil)
}
#IBAction func backButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
#objc func saveFIRData() {
guard let image = imageView1.image else { return }
self.uploadProfileImage(image){ url in
self.saveProfileImage(profileURL: url!){ success in
if success != nil{
print("yes")
}
}
}
}
}
extension NewEditProfileViewController {
func uploadProfileImage(_ image:UIImage, completion: #escaping (_ url: URL?)->()) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let storageRef = Storage.storage().reference().child("users/\(uid)")
let imageData = imageView1.image?.jpegData(compressionQuality: 0.8)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
storageRef.putData(imageData!, metadata: metaData) { (metaData, error) in
if error == nil{
print("success")
storageRef.downloadURL(completion: { (url, error) in
completion(url)
})
}else{
print("error in save image")
completion(nil)
}
}
}
func saveProfileImage(profileURL:URL, completion: #escaping ((_ url: URL?) -> ())){
guard let uid = Auth.auth().currentUser?.uid else { return }
let databaseRef = Database.database().reference().child("users/profilePhotoURL/\(uid)")
let userObject = [
"photoURL": profileURL.absoluteString
] as [String:Any]
self.ref.child("users").child(uid).setValue(userObject)
}
}
As I can see in your code in function
func saveProfileImage(profileURL:URL, completion: #escaping ((_ url: URL?) -> ()))
code to download image is missing you have to update your saveProfileImageto support download & then save to local app directory.
func saveProfileImage(profileURL:URL, completion: #escaping ((_ url: URL?) -> ())){
guard let uid = Auth.auth().currentUser?.uid else { return }
let databaseRef = Storage.storage().reference().child("users/profilePhotoURL/\(uid)")
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes), Change it according to your need
storageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Save `data` to your local directory here
let imageFilename = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/" + "\(uid).jpg"
data.write(toFile: imageFilename, atomically: true)
}
}
let userObject = [
"photoURL": profileURL.absoluteString
] as [String:Any]
self.ref.child("users").child(uid).setValue(userObject)
}
}
Refer following sample code taken from Firebase guide Download to local section on file "Download File on iOS" page.
// Create a reference to the file you want to download
let islandRef = storageRef.child("images/island.jpg")
// Create local filesystem URL
let localURL = URL(string: "path/to/image")!
// Download to the local filesystem
let downloadTask = islandRef.write(toFile: localURL) { url, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Local file URL for "images/island.jpg" is returned
}
}
I have a UIImagePicker set up within my app that works fine. I would like to upload a profile picture to Firebase when my UIImage picker has been chosen. Here is my function for when a picture has been selected.
//image picker did finish code
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
profilePic.contentMode = .ScaleAspectFill
profilePic.image = chosenImage
profilePic.hidden = false
buttonStack.hidden = true
changeButtonView.hidden = false
self.statusLabel.text = "Here is Your Profile Picture"
dismissViewControllerAnimated(true, completion: nil)
}
The new documentation states that we need to declare a NSURl in order to upload a file. Here is my attempt to find the NSURL of the given file, but it doesn't work. Here is the documentation and a link to it:https://firebase.google.com/docs/storage/ios/upload-files#upload_from_data_in_memory
// File located on disk
let localFile: NSURL = ...
// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putFile(localFile, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL
}
}
Here is my attempt for retrieving the NSURL of the UIImagePicker:
//image picker did finish code
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
//getting the object's url
let imageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String;
let photoUrl = NSURL(fileURLWithPath: documentDir)
let localPath = photoUrl.URLByAppendingPathComponent(imageName!)
self.localFile = localPath
profilePic.contentMode = .ScaleAspectFill
profilePic.image = chosenImage
profilePic.hidden = false
buttonStack.hidden = true
changeButtonView.hidden = false
self.statusLabel.text = "Here is Your Profile Picture"
dismissViewControllerAnimated(true, completion: nil)
}
I believe that I am also running into difficulties if the image was taken from the camera instead of the gallery since it is not saved on the device yet. How do I find this image/snapshots's NSURL?
Here is my method to upload and download the user profile photo from firebase storage:
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
userPhoto.image = image
dismissViewControllerAnimated(true, completion: nil)
var data = NSData()
data = UIImageJPEGRepresentation(userPhoto.image!, 0.8)!
// set upload path
let filePath = "\(FIRAuth.auth()!.currentUser!.uid)/\("userPhoto")"
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
self.storageRef.child(filePath).putData(data, metadata: metaData){(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
}else{
//store downloadURL
let downloadURL = metaData!.downloadURL()!.absoluteString
//store downloadURL at database
self.databaseRef.child("users").child(FIRAuth.auth()!.currentUser!.uid).updateChildValues(["userPhoto": downloadURL])
}
}
}
I also store the Image URL into firebase database and check if the user has a profile photo or you might get a crash:
//get photo back
databaseRef.child("users").child(userID!).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// check if user has photo
if snapshot.hasChild("userPhoto"){
// set image locatin
let filePath = "\(userID!)/\("userPhoto")"
// Assuming a < 10MB file, though you can change that
self.storageRef.child(filePath).dataWithMaxSize(10*1024*1024, completion: { (data, error) in
let userPhoto = UIImage(data: data!)
self.userPhoto.image = userPhoto
})
}
})
Simple 2020 example
Don't forget to add pod 'Firebase/Storage' to your podfile, and pod install
Add two delegates to your class
class YourScreen: UIViewController,
UIImagePickerControllerDelegate, UINavigationControllerDelegate {
Storyboard, button, link to ...
#IBAction func tapCameraButton() {
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
and then
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let im: UIImage = info[.editedImage] as? UIImage else { return }
guard let d: Data = im.jpegData(compressionQuality: 0.5) else { return }
let md = StorageMetadata()
md.contentType = "image/png"
let ref = Storage.storage().reference().child("someFolder/12345678.jpg")
ref.putData(d, metadata: md) { (metadata, error) in
if error == nil {
ref.downloadURL(completion: { (url, error) in
print("Done, url is \(String(describing: url))")
})
}else{
print("error \(String(describing: error))")
}
}
dismiss(animated: true)
}
But where do you put the image?
At the code,
... .child("someFolder/12345678.jpg")
Almost inevitably,
• as the folder name use the user's id, the chat id, the feed id or a similar concept
• for the name, the only possibility is a uuid
Hence almost always
let f = chatId + "/" + UUID().uuidString + ".jpg"
let ref = Storage.storage().reference().child(f)
Working in Swift 4.2
Here i am doing click on image i have added tapGesture then it open gallery then selected image that upload in Firebase and also i add textField Value Too i hope it helps you Thank You
import UIKit
import Firebase
class ViewController: UIViewController {
#IBOutlet var myImageView: UIImageView!
#IBOutlet var txtText: UITextField!
var ref = DatabaseReference.init()
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.openGalleryClick(tapGesture:)))
myImageView.isUserInteractionEnabled = true
myImageView.addGestureRecognizer(tapGestureRecognizer)
myImageView.backgroundColor = UIColor.red
}
#objc func openGalleryClick(tapGesture: UITapGestureRecognizer){
self.setupImagePicker()
}
#IBAction func btnSaveClick(_ sender: UIButton) {
self.saveFIRData()
}
func saveFIRData(){
self.uploadMedia(image: myImageView.image!){ url in
self.saveImage(userName: self.txtText.text!, profileImageURL: url!){ success in
if (success != nil){
self.dismiss(animated: true, completion: nil)
}
}
}
}
func uploadMedia(image :UIImage, completion: #escaping ((_ url: URL?) -> ())) {
let storageRef = Storage.storage().reference().child("myimage.png")
let imgData = self.myImageView.image?.pngData()
let metaData = StorageMetadata()
metaData.contentType = "image/png"
storageRef.putData(imgData!, metadata: metaData) { (metadata, error) in
if error == nil{
storageRef.downloadURL(completion: { (url, error) in
completion(url)
})
}else{
print("error in save image")
completion(nil)
}
}
}
func saveImage(userName:String, profileImageURL: URL , completion: #escaping ((_ url: URL?) -> ())){
let dict = ["name": "Yogesh", "text": txtText.text!, "profileImageURL": profileImageURL.absoluteString] as [String : Any]
self.ref.child("chat").childByAutoId().setValue(dict)
}
}
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate{
func setupImagePicker(){
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){
imagePicker.sourceType = .savedPhotosAlbum
imagePicker.delegate = self
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
myImageView.image = image
picker.dismiss(animated: true, completion: nil)
}
}