Good Afternoon, I am trying to allow users to save their profile picture in firebase. my application runs without a crash. however, when I select a picture it doesn't save to the system. I have a ViewController, and an extension file that I have been placing my code in. I will place below. Please help me understand what I am doing wrong. Hopefully, this question will help others who are facing the same issues.
import UIKit
import Firebase
class EditProfileVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupProfileImageView()
self.view.backgroundColor = UIColor.white
}
func setupProfileImageView() {
view.addSubview(profileImageView)
profileImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
profileImageView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100).isActive=true
profileImageView.widthAnchor.constraint(equalToConstant: 120).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 120).isActive = true
profileImageView.layer.cornerRadius = 60
profileImageView.layer.masksToBounds = true
var randomString = UUID().uuidString
let storageRef = Storage.storage().reference().child;"\(randomString).png")
if let uploadImage = UIImagePNGRepresentation(self.profileImageView.image!) {
storageRef.putData(uploadImage, metadata: nil) { (metadata, error) in
if error != nil {
print("Error upload data to Firebase Storage. Detail: \(String(describing: error))")
return
}
if let profileImageURl = metadata?.downloadURL()?.absoluteString {
self.registerUser(UserId: userId, profileImageURL: profileImageURL) {
}
}
}
}
}
lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "users")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView)))
imageView.isUserInteractionEnabled = true
return imageView
}()
}
// This is my extension file
import UIKit
import Firebase
extension EditProfileVC: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
#objc func handleSelectProfileImageView() {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicker: UIImage?
dismiss(animated: true, completion: nil)
if let editedImage = info["UIImagePickerControllerEditedImage"] {
selectedImageFromPicker = editedImage as? UIImage
} else if let originalImage = info["UIImagePickerControllerOriginalImage"] {
selectedImageFromPicker = originalImage as? UIImage
}
if let selectedImage = selectedImageFromPicker {
profileImageView.image = selectedImage
}
print(info)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("Canceled Picker")
dismiss(animated: true, completion: nil)
}
}
My app doesn't crash when I run it. It's just no images are stored in firebase. I want users to click onto the EditProfileVC, then be able to change their profile picture and have it save. If anyone can help me solve this issue, it would be greatly appreciated.
Related
The user can select a picture as a profile picture in my app.
After that he can click on done and the picture gets uploaded.
If the user does not select a picture my code still upload a blank picture by clicking on done.
How can I check if the user selected a picture and then trigger the function?
I need an if else statement but don't know how to get the status "is a picture selected?"
I could maybe also use a default value. But that would mean to download the actual picture and reupload it again as default. That does not sound good.
#IBOutlet weak var tapToChangeProfileButton: UIButton!
var imagePicker: UIImagePickerController!
var ref: DatabaseReference!
#IBAction func updateProfile(_ sender: UIButton) {
uploadPic(arg: true, completion: { (success) -> Void in
if success {
addUrlToFirebaseProfile()
} else {
}
})
func uploadPic(arg: Bool, completion: #escaping (Bool) -> ()) {
guard let imageSelected = self.image else {
completion(false);
return
}
guard let imageData = imageSelected.jpegData(compressionQuality: 0.1) else {
completion(false);
return
}
let storageRef = Storage.storage().reference(forURL: "gs://....e.appspot.com")
let storageProfileRef = storageRef.child("profilePictures").child(Auth.auth().currentUser!.uid)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
storageProfileRef.putData(imageData, metadata: metadata, completion: {
(storageMetadata, error) in
if error != nil {
//print(error?.localizedDescription)
completion(false);
return
}
storageProfileRef.downloadURL(completion: { (url, error) in
if let metaImageURL = url?.absoluteString {
print(metaImageURL)
self.urltoPicture = metaImageURL
completion(true)
}
else
{
completion(false); return
}
})
})
}
func addUrlToFirebaseProfile(){
ref = Database.database().reference()
let userID = Auth.auth().currentUser!.uid
ref.child("user/\(userID)").updateChildValues(["profileText": profileText.text!])
print(urltoPicture)
ref.child("user/\(userID)").updateChildValues(["picture": urltoPicture])
}
self.navigationController?.popViewController(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
let imageTap = UITapGestureRecognizer(target: self, action: #selector(openImagePicker))
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(imageTap)
tapToChangeProfileButton.addTarget(self, action: #selector(openImagePicker), for: .touchUpInside)
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = true
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
}
#objc func openImagePicker(_ sender:Any){
self.present(imagePicker, animated: true, completion: nil)
}
extension ImagePickerViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
picker.dismiss(animated: true, completion: nil)
}
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any])
{
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.profileImageView.image = pickedImage
image = pickedImage
}
picker.dismiss(animated: true, completion: nil)
}
}
As I see from your code, whenever you get an image from imagePickerController you store it into variable self.image. Then whenever you click Done you just upload this self.image
Make variable self.image can be nil then remember to unset it after uploading successfully
Code will be like this
var image : UIImage? = nil
#IBAction func updateProfile(_ sender: UIButton) {
uploadPic(arg: true, completion: { (success) -> Void in
if success {
addUrlToFirebaseProfile()
self.image = nil // reset image to nil if success
} else {
}
})
}
You are setting self.image if the user selects a photo.
But you are not unsetting self.image if the user doesn't select a photo. It needs to be set to nil (not to an empty UIImage()).
I'm new to coding and trying to build an iOS App. I am storing images uploaded by users into my firebase storage and then saving the URL as a string ("https//.....). I am able to get a snapshot to show up in project terminal after I use print(snapshot). It prints, snap (profileImageUrl) https://firebasestorage.... How do I use this snapshot to get the ImageView to show the profile picture most recently saved?
import UIKit
import Firebase
import SDWebImage
class EditProfileViewController: UIViewController {
#IBOutlet weak var ProfileImage: UIImageView!
var selectedImage: UIImage?
var ref:DatabaseReference?
var databaseHandle:DatabaseHandle = 0
var postProfileImage = [String]()
let dbref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
self.ref?.child("users").child(Auth.auth().currentUser!.uid).child("profileImageUrl").observe(.value, with: { (snapshot) in
print(snapshot)
})
ProfileImage.layer.borderWidth = 3.0
ProfileImage.layer.masksToBounds = false
ProfileImage.layer.borderColor = UIColor.white.cgColor
ProfileImage.layer.cornerRadius = ProfileImage.frame.size.width / 2
ProfileImage.clipsToBounds = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(EditProfileViewController.handleSelectProfileImageView))
ProfileImage.addGestureRecognizer(tapGesture)
ProfileImage.isUserInteractionEnabled = true
}
#objc func handleSelectProfileImageView() {
let pickerController = UIImagePickerController()
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
#IBAction func Cancel(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
let user = Auth.auth().currentUser
let fileData = NSData()
#IBAction func DoneButton(_ sender: UIBarButtonItem) {
guard let imageSelected = self.ProfileImage.image else {
print ("Avatar is nil")
return
}
var dict: Dictionary<String, Any> = [
"profileImageUrl": "",
]
guard let imageData = imageSelected.jpegData(compressionQuality: 0.4) else {
return
}
let storageRef = Storage.storage().reference(forURL: "(I have my storage url here")
let imageName = NSUUID().uuidString
let storageProfileRef = storageRef.child("Profile_Images").child(Auth.auth().currentUser!.uid).child("\(imageName).png")
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
storageProfileRef.putData(imageData, metadata: metadata, completion:
{ (StorageMetadata, error) in
if (error != nil) {
return
}
storageProfileRef.downloadURL { (url, error) in
if let metaImageUrl = url?.absoluteString {
dict["profileImageUrl"] = metaImageUrl
Database.database().reference().child("users").child(Auth.auth().currentUser!.uid).updateChildValues(dict, withCompletionBlock: {
(error, ref) in
if error == nil {
print("Done")
}
}
)
}
}
})
dismiss(animated: true, completion: nil)
}
}
extension EditProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//print("did Finish Picking Media")
if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerOriginalImage")] as? UIImage{
selectedImage = image
ProfileImage.image = image
}
dismiss(animated: true, completion: nil)
}
}
I could really use some help!
You can add an extension to UIImageView as below:
extension UIImageView {
func load(url: URL, onLoadCompletion: ((_ isImageLoaded: Bool) -> Void)? = nil) {
self.image = nil
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
onLoadCompletion?(true)
}
} else {
onLoadCompletion?(false)
}
} else {
onLoadCompletion?(false)
}
}
}
}
Assuming your image view outlet is something like this:
#IBOutlet weak var imageView: UIImageView!
Below is the usage when adding a loader:
if let url = URL(string: "https://firebase-storage-url") {
// show a loader here if needed
imageView.load(url: url) { (imageLoaded) in
if imageLoaded {
// hide loader
} else {
// show a place holder image
// hide loader
}
}
} else {
// show a default image
}
Below is the usage without any extra work and just loading the image:
if let url = URL(string: "https://firebase-storage-url") {
imageView.load(url: url)
}
I tried to make an image classification app. For some reason, the classification label doesn't show any results. Below is my code, would appreciate all your helps.enter image description here
===
import UIKit
import CoreML
import Vision
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var myImageView: UIImageView!
let picker = UIImagePickerController()
#IBAction func cameraButton(_ sender: UIBarButtonItem) {
let vc = UIImagePickerController()
vc.sourceType = .camera
vc.allowsEditing = false
vc.delegate = self
present(vc, animated: true)
}
#IBAction func photoButton(_ sender: UIBarButtonItem) {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
present(picker, animated: true, completion: nil)
}
#IBOutlet weak var classificationLabel: UILabel!
/// Image classification
lazy var classificationRequest: VNCoreMLRequest = {
do {
let model = try VNCoreMLModel(for: AnimalClassifier().model)
let request = VNCoreMLRequest(model: model, completionHandler: { [weak self] request, error in
self?.processClassifications(for: request, error: error)
})
request.imageCropAndScaleOption = .centerCrop
return request
} catch {
fatalError("Failed to load Vision ML model: \(error)")
}
}()
func updateClassifications(for Image: UIImage) {
classificationLabel.text = "Classifying..."
let orientation = CGImagePropertyOrientation(Image.imageOrientation)
guard let ciImage = CIImage(image: Image) else { fatalError("Unable to create \(CIImage.self) from \(Image).") }
DispatchQueue.global(qos: .userInitiated).async {
let handler = VNImageRequestHandler(ciImage: ciImage, orientation: orientation)
do {
try handler.perform([self.classificationRequest])
} catch {
print("Failed to perform classification.\n\(error.localizedDescription)")
}
}
}
func processClassifications(for request: VNRequest, error: Error?) {
DispatchQueue.main.async {
guard let results = request.results else {
self.classificationLabel.text = "Unable to classify image.\n\(error!.localizedDescription)"
return
}
let classifications = results as! [VNClassificationObservation]
if classifications.isEmpty {
self.classificationLabel.text = "Nothing recognized."
} else {
// Display top classifications ranked by confidence in the UI.
let topClassifications = classifications.prefix(2)
let descriptions = topClassifications.map { classification in
// Formats the classification for display; e.g. "(0.37) cliff, drop, drop-off".
return String(format: " (%.2f) %#", classification.confidence, classification.identifier)
}
self.classificationLabel.text = "Classification:\n" + descriptions.joined(separator: "\n")
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var Image: UIImage
if let possibleImage = info[.editedImage] as? UIImage {
Image = possibleImage
} else if let possibleImage = info[.originalImage] as? UIImage {
Image = possibleImage
} else {
return
}
myImageView.image = Image
dismiss(animated: true)
updateClassifications(for: Image)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
To make your label support multiple lines you need to set the property numberOfLines to 0. So in viewDidLoad for instance do
classificationLabel.numberOfLines = 0
I am using custom CropViewController open source imagePicker for photos, and for video I'm trying to use default imagePicker provided by Swift itself since CropViewController doesn't have video option.
After I pick a video from photo library, three buttons shown at the bottom (cancel, play, select). Play button and select button works perfectly but cancel won't work.
Here is my code to trigger imagePickerController for both photo and video.
#objc func videoPresentPicker() {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
picker.mediaTypes = [kUTTypeMovie as String]
picker.allowsEditing = true
self.present(picker, animated: true, completion: nil)
}
#objc func photoPresentPicker() {
self.croppingStyle = .default
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
picker.allowsEditing = false
self.present(picker, animated: true, completion: nil)
}
I am truly appreciated for you help. I have been struggling for few days and finally reaching out for some helps...
Update
extension ChatViewController: CropViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
internal func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let videoUrl = info[UIImagePickerController.InfoKey.mediaURL] as? NSURL {
let data = NSData(contentsOf: videoUrl as URL)!
print("File size before compression: \(Double(data.length / 1048576)) mb")
let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".m4v")
self.compressVideo(inputURL: videoUrl as URL, outputURL: compressedURL) { (exportSession) in
guard let session = exportSession else {
return
}
switch session.status {
case .unknown:
break
case .waiting:
break
case .exporting:
break
case .completed:
guard let compressedData = NSData(contentsOf: compressedURL) else {
return
}
print("File size after compression: \(Double(compressedData.length / 1048576)) mb")
case .failed:
break
case .cancelled:
break
#unknown default:
break
}
}
} else {
guard let image = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) else { return }
let cropController = CropViewController(croppingStyle: croppingStyle, image: image)
cropController.delegate = self
imageView.image = image
picker.dismiss(animated: true, completion: {
self.present(cropController, animated: true, completion: nil)
if self.inputTextField.isFirstResponder == true {
self.handleKeyboardWillShow()
}
})
}
transparentView.alpha = 0
self.tableView.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
dismiss(animated: true, completion: nil)
}
Just implement this function
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated:true, completion: nil)
}
When I save, my image to coreData, when I re-open it from CoreData, all image who was took in portrait, are in landscape orientation.
I fund lot of previews question a bout it but all in Objective C not in Swift.
How can I fix the problem?
This is my code: ( it is also a text application when it work I will add it to my project)
This text app has two image view one for loading from library and one for loading from coreData.
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
var monimage: String!
let imagePicker = UIImagePickerController()
#IBOutlet weak var MaPhoto: UIImageView? = UIImageView()
#IBOutlet weak var maPhoto2: UIImageView! = UIImageView()
var cameraUI:UIImagePickerController = UIImagePickerController()
var yourContacts:NSMutableArray = NSMutableArray()
override func viewDidLoad() {
imagePicker.delegate = self
super.viewDidLoad()
}
#IBAction func LabraryImage(sender: AnyObject) {
imagePicker.delegate = self
imagePicker.sourceType = .PhotoLibrary
imagePicker.allowsEditing = true
presentViewController(imagePicker, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func takePhoto(sender: UIButton) {
if (UIImagePickerController.isSourceTypeAvailable(.Camera)){
cameraUI = UIImagePickerController()
cameraUI.delegate = self
cameraUI.sourceType = UIImagePickerControllerSourceType.Camera
cameraUI.allowsEditing = true
self.presentViewController(cameraUI, animated: true, completion: nil)
}else{
//no camera available
let alert = UIAlertController(title: "Error", message: "There is no camera available", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Okay", style: .Default, handler: {(alertAction)in
alert.dismissViewControllerAnimated (true, completion: nil)
}))
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
MaPhoto!.contentMode = .ScaleAspectFit
MaPhoto!.image = pickedImage
}
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func btnSavePressed(sender : AnyObject) {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let ent = NSEntityDescription.entityForName("ImageData", inManagedObjectContext: context)
var newUser = ImageData (entity: ent!, insertIntoManagedObjectContext: context)
let contactImageData:NSData = UIImagePNGRepresentation(MaPhoto!.image)
newUser.monimage = contactImageData
context.save(nil)
self.navigationController?.popViewControllerAnimated(true)
}
#IBAction func loadImage(sender: AnyObject){
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let request2 = NSFetchRequest (entityName: "ImageData")
request2.returnsObjectsAsFaults = false;
var results2:NSArray = context.executeFetchRequest(request2, error: nil)!
if results2.count > 0 {
for user in results2{
var thisUser2 = user as! ImageData
let profileImage:UIImage = UIImage(data: thisUser2.monimage)!
maPhoto2.image = profileImage
}
}
}
I also working to get the image square so it is for that "allowEditing is = true"
Thank s for your help!
this is the answer to my question:
#IBAction func btnSavePressed(sender : AnyObject) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("ImageData",
inManagedObjectContext: managedContext)
let options = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
var newImageData = UIImageJPEGRepresentation(MaPhoto!.image,1)
options.setValue(newImageData, forKey: "monimage")
var error: NSError?
managedContext.save(&error)
}
JPGs are great for photos. However, saving in jpeg might loose some quality which png tends to excel as it has a lossless compression format.
Its just a matter of preference and what you need at the moment. If you don't want to convert to jpg you can call this method then convert to pngData to preserve orientation before saving to coreData. :)
func rotatedCopy() -> UIImage {
if self.imageOrientation == UIImage.Orientation.up {
return self
}
UIGraphicsBeginImageContext(size)
//draws the image in current context respecting orientation
draw(in: CGRect(origin: CGPoint.zero, size: size))
let copy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return copy!
}