How to send multiple images to Firebase and retrieve them in the UIImageView in Swift - swift

I have an app that lets users choose multiple images. The problem is that it doesn't upload and save the image to the user in Firebase and retrieve the image.
This is my code:
import UIKit
import Photos
import Firebase
import BSImagePicker
class Downloadimages: UIViewController {
#IBOutlet weak var imgView: UIImageView!
var ref: DatabaseReference?
var SelectedAssets = [PHAsset]()
var PhotoArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addImagesClicked(_ sender: Any) {
// create an instance
let vc = BSImagePickerViewController()
//display picture gallery
self.bs_presentImagePickerController(vc, animated: true,
select: { (asset: PHAsset) -> Void in
}, deselect: { (asset: PHAsset) -> Void in
// User deselected an assets.
}, cancel: { (assets: [PHAsset]) -> Void in
// User cancelled. And this where the assets currently selected.
}, finish: { (assets: [PHAsset]) -> Void in
// User finished with these assets
for i in 0..<assets.count
{
self.SelectedAssets.append(assets[i])
}
self.convertAssetToImages()
}, completion: nil)
let image = UIImagePickerController()
image.delegate = self as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
{
//after its completed
}
}
#objc(imagePickerController:didFinishPickingMediaWithInfo:) func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage
{
imgView.image = image
}
else
{
//error
}
self.dismiss(animated: true, completion: nil)
let storageRef = Storage.storage().reference().child("myImage.png")
if let uploadData = UIImagePNGRepresentation(self.imgView.image!){
storageRef.putData(uploadData, metadata: nil, completion:
{
(metadata, error) in
if error != nil {
print("error")
return
}
print(metadata!)
//how do I put the download URL in the metadata into my database
}
)
}
}
func convertAssetToImages() -> Void {
if SelectedAssets.count != 0{
for i in 0..<SelectedAssets.count{
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var thumbnail = UIImage()
option.isSynchronous = true
manager.requestImage(for: SelectedAssets[i], targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: option, resultHandler: {(result, info)->Void in
thumbnail = result!
})
let data = UIImageJPEGRepresentation(thumbnail, 0.7)
let newImage = UIImage(data: data!)
self.PhotoArray.append(newImage! as UIImage)
}
self.imgView.animationImages = self.PhotoArray
self.imgView.animationDuration = 3.0
self.imgView.startAnimating()
}
print("complete photo array \(self.PhotoArray)")
}
}
and this is my post code
import Foundation
class Post {
var id:String
var author:UserProfile
var text:String
var createdAt:Date
init(id:String, author:UserProfile,text:String,timestamp:Double) {
self.id = id
self.author = author
self.text = text
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, _ data:[String:Any]) -> Post? {
if let author = data["author"] as? [String:Any],
let uid = author["uid"] as? String,
let username = author["username"] as? String,
let photoURL = author["photoURL"] as? String,
let url = URL(string:photoURL),
let text = data["text"] as? String,
let timestamp = data["timestamp"] as? Double {
let userProfile = UserProfile(uid: uid, username: username, photoURL: url)
return Post(id: key, author: userProfile, text: text, timestamp:timestamp)
}
return nil
}
}
this is my userProfile
import Foundation
class UserProfile {
var uid:String
var username:String
var photoURL:URL
init(uid:String, username:String,photoURL:URL) {
self.uid = uid
self.username = username
self.photoURL = photoURL
}
}
and this is
import Foundation
import Firebase
class UserService {
static var currentUserProfile:UserProfile?
static func observeUserProfile(_ uid:String, completion: #escaping ((_ userProfile:UserProfile?)->())) {
let userRef = Database.database().reference().child("users/profile/\(uid)")
userRef.observe(.value, with: { snapshot in
var userProfile:UserProfile?
if let dict = snapshot.value as? [String:Any],
let username = dict["username"] as? String,
let photoURL = dict["photoURL"] as? String,
let url = URL(string:photoURL) {
userProfile = UserProfile(uid: snapshot.key, username: username, photoURL: url)
}
completion(userProfile)
})
}
}

Related

Realm list data in Swift is saving but not loading properly. New to this and not sure what the problem is. Code below

Below is my main view controller. The user selects images of clothing which are then categorized using CoreML and given a filename. Then, data is saved to Realm. When I call the function loadClothing(), the array is empty even though items were added during func detect. Any help is much appreciated!
import UIKit
import PhotosUI
import RealmSwift
import CoreML
import Vision
class ViewController: UIViewController, PHPickerViewControllerDelegate {
#IBOutlet weak var shoesImageView: UIImageView!
#IBOutlet weak var shirtImageView: UIImageView!
#IBOutlet weak var pantsImageView: UIImageView!
var documentsUrl: URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
let realm = try! Realm()
var clothing: Results<Clothing>?
override func viewDidLoad() {
super.viewDidLoad()
loadClothing()
let clothingArray = Clothing()
print(clothingArray)
}
#IBAction func addClothesButton(_ sender: UIBarButtonItem) {
pickPhotos()
}
#IBAction func randomizeButton(_ sender: UIBarButtonItem) {
loadClothing()
let clothingArray = Clothing()
print(clothingArray)
shirtImageView.image = load(fileName: clothingArray.shirtImages.randomElement()!)
pantsImageView.image = load(fileName: clothingArray.pantsImages.randomElement()!)
shoesImageView.image = load(fileName: clothingArray.shoesImages.randomElement()!)
}
//MARK: - PHPickerViewController
#objc func pickPhotos() {
var config = PHPickerConfiguration()
config.selectionLimit = 25
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = self
self.present(pickerViewController, animated: true, completion: nil)
}
// MARK: - PHPickerViewControllerDelegate
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
for result in results {
result.itemProvider.loadObject(ofClass: UIImage.self) {(object, error) in
if let image = object as? UIImage {
DispatchQueue.main.async {
guard let fileName = result.itemProvider.suggestedName else {
fatalError("Could not retrieve file name.")
}
print(fileName)
guard let ciImage = CIImage(image: image) else {
fatalError("Could not convert to CI Image.")
}
self.detect(image: ciImage, fileName: fileName)
}
}
}
}
}
// MARK: - Core ML
func detect(image: CIImage, fileName: String) {
guard let model = try? VNCoreMLModel(for: ClothingClassifier(configuration: MLModelConfiguration()).model) else {
fatalError("Loading CoreML Model failed.")
}
let request = VNCoreMLRequest(model: model) { (request, error) in
guard let results = request.results as? [VNClassificationObservation] else {
fatalError("Model failed to process image.")
}
let newClothing = Clothing()
if let firstResult = results.first {
let uiImage = UIImage(ciImage: image)
if firstResult.identifier.contains("shirts") {
newClothing.shirtImages.append(fileName)
} else if firstResult.identifier.contains("pants"){
newClothing.pantsImages.append(fileName)
} else if firstResult.identifier.contains("shoes") {
newClothing.shoesImages.append(fileName)
}
self.save(clothing: newClothing)
print(newClothing)
}
}
let handler = VNImageRequestHandler(ciImage: image)
do {
try handler.perform([request])
}
catch {
print(error)
}
}
// MARK: - Data Manipulation Methods
func save(clothing: Clothing) {
do {
try realm.write {
realm.add(clothing)
}
} catch {
print("Error saving uploaded clothing. \(error)")
}
}
func loadClothing() {
clothing = realm.objects(Clothing.self)
print("loaded")
}
private func load(fileName: String) -> UIImage? {
let fileURL = documentsUrl.appendingPathComponent(fileName)
do {
let imageData = try Data(contentsOf: fileURL)
return UIImage(data: imageData)
} catch {
print("Error loading image : \(error)")
}
return nil
}
}
Clothing Class
import Foundation
import RealmSwift
class Clothing: Object {
let shirtImages = List<String>()
let pantsImages = List<String>()
let shoesImages = List<String>()
}

AlertController view is not in the window hierarchy

i am a beginner in swift, i was trying to use an UIAlertController but i have got an error and the UiAlertController do not show up and i can see an error in the console that says
2021-06-20 18:16:28.494162+0200 Bicycall[50670:543648] [Presentation] Attempt to present <UIAlertController: 0x7fbaca034e00> on <Bicycall.login: 0x7fbabb01d800> (from <Bicycall.login: 0x7fbabb01d800>) whose view is not in the window hierarchy.
2021-06-20 18:16:28.494339+0200 Bicycall[50670:543648] [Presentation] Attempt to present <UIAlertController: 0x7fbac9862800> on <Bicycall.login: 0x7fbabb01d800> (from <Bicycall.login: 0x7fbabb01d800>) whose view is not in the window hierarchy.
Here what i have tried:
import UIKit
import CoreData
import AVKit
import AVFoundation
import TKSubmitTransition
class login: UIViewController {
#IBOutlet weak var passwordView: UIView!
#IBOutlet weak var emailView: UIView!
var id: Int?
var name: String?
var lastname: String?
var email:String?
var password:String?
var phone:String?
var u = ConnectedUser()
var BR = BaseUrl.baseUrl
var player: AVPlayer?
let videoURL: NSURL = Bundle.main.url(forResource: "Bikers", withExtension: "mp4")! as NSURL
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
func presentTestAlert(_ title: String, _ message: String){
let alert = UIAlertController(title: title , message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"), style: .default, handler: { _ in
NSLog("The \"OK\" alert occured.")
}))
DispatchQueue.main.async {
self.getTopMostViewController()?.present(alert, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.DeleteAllData()
player = AVPlayer(url: videoURL as URL)
player?.actionAtItemEnd = .none
player?.isMuted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
playerLayer.zPosition = -1
playerLayer.frame = view.frame
view.layer.addSublayer(playerLayer)
player?.play()
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: .main) { [weak self] _ in
self?.player?.seek(to: CMTime.zero)
self?.player?.play()
// Do any additional setup after loading the view.
}
emailView.layer.cornerRadius = 30.0
emailView.layer.borderWidth = 0.5
emailView.layer.borderColor = UIColor.white.cgColor
passwordView.layer.cornerRadius = 30.0
passwordView.layer.borderWidth = 0.5
passwordView.layer.borderColor = UIColor.white.cgColor
}
//widgets
#IBOutlet weak var txtEmail: UITextField!
#IBOutlet weak var txtPassword: UITextField!
//Actions
#IBAction func btnLogin(_ sender: Any){
//get
/*
guard let url = URL(string: "http://localhost:3000/bikes") else {
return
}
let session = URLSession.shared
session.dataTask(with: url) { ( data , response ,error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do
{
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
}catch{
print(error)
}
}
}.resume()
*/
//post
guard let url = URL(string: BR+"/login") else {
return
}
let bodyparameters = ["email": txtEmail.text, "password": txtPassword.text]
if (txtEmail.text!.isEmpty || txtPassword.text!.isEmpty ){
self.presentTestAlert("Wrong credentials","Email and Password must not be empty")
}else{
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: bodyparameters, options: []) else{
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data,response,error) in
let status = (response as! HTTPURLResponse).statusCode
//print(response)
print(status)
if let response = response {
let status = (response as! HTTPURLResponse).statusCode
//print(response)
print(status)
}
if((status) == 200){
self.presentTestAlert("Connection Success", " internet connection")
print(" Connection Successssssssssssssss")
if let data = data {
do {
//let json = try JSONSerialization.jsonObject(with: data, options: [])
// print(json);
print(data)
let user = try JSONDecoder().decode(User.self, from: data)
DispatchQueue.main.async {
self.id = user.user_id
self.name = user.name
self.lastname = user.lastname
self.email = user.email
self.password = user.password
self.phone = user.phone
print(self.id!)
print(self.email!)
if(user.user_id != 0){
self.saveUser()
self.DisplayConnectedUser()
self.performSegue(withIdentifier: "HomeSegue", sender: "nil")
}else{
self.presentTestAlert("Login Failed","Wrong credentials")
}
}
}catch{
print(error)
}
}
}else {
self.presentTestAlert("No Connection", "No internet connection")
print(" Connection Nooooooooooooooooooooooooo")
}
}.resume()
}
}
func DeleteAllData(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let DelAllReqVar = NSBatchDeleteRequest(fetchRequest: NSFetchRequest<NSFetchRequestResult>(entityName: "Users"))
do {
try managedContext.execute(DelAllReqVar)
}
catch {
print(error)
}
}
func saveUser() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//represente l'ORM
let persistentContainer = appDelegate.persistentContainer
let managedContext = persistentContainer.viewContext
let entityDescription = NSEntityDescription.entity(forEntityName: "Users" , in: managedContext)
let object = NSManagedObject(entity: entityDescription! , insertInto: managedContext )
object.setValue(id! , forKey: "user_id" )
object.setValue(email! , forKey: "email" )
object.setValue(password! , forKey: "password" )
object.setValue(name! , forKey: "name" )
object.setValue(lastname! , forKey: "lastname" )
object.setValue(phone! , forKey: "phone" )
do {
try managedContext.save()
print("INSERT SUCCESSFULLY")
print(id!)
}
catch {
print("INSERT ERROR")
}
}
#IBAction func btnSignup(_ sender: Any) {
performSegue(withIdentifier: "signupSegue", sender: "nil")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
func DisplayConnectedUser() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//represente l'ORM
let persistentContainer = appDelegate.persistentContainer
let managedContext = persistentContainer.viewContext //retourne NSManagedObject toujours
//la requete retourne un NSManagedObject
let request = NSFetchRequest<NSManagedObject>(entityName : "Users")
//execution de la requete
do {
let result = try managedContext.fetch(request)
for item in result {
print(item.value(forKey: "user_id") as! Int )
print(item.value(forKey: "email") as! String)
self.u.user_id = (item.value(forKey: "user_id") as! Int)
self.u.email = (item.value(forKey: "email") as! String)
self.u.password = (item.value(forKey: "password") as! String)
self.u.name = (item.value(forKey: "name") as! String)
self.u.lastname = (item.value(forKey: "lastname") as! String)
self.u.phone = (item.value(forKey: "phone") as! String)
print(self.u.user_id!)
print(self.u.email!)
print(self.u.password!)
print(self.u.name!)
print(self.u.lastname!)
print(self.u.phone!)
}
}
catch {
print("NO DATA FOUND , Error")
}
}
}
What is annoying me is that none of my alerts worked! i read some other answer in stackoverflow but the solutions did not work for me
What i am trying is to make my alerts working good
Any help will be so appreciated
It seems you want to present the alert over the video player (playerLayer) but you are calling your alert over the layer behind the playerLayer, it will give you the error that you're getting.
With reference to Swift 4 Attempt to present ViewController whose view is not in the window hierarchy
Add this function in your code
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
And replace (Line 33)
self.present(alert, animated: true, completion: nil)
with
DispatchQueue.main.async {
getTopMostViewController()?.present(alert, animated: true, completion: nil)
}

How to use a stored url from Firebase Database as an image in an UIImageView

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

Saving Profile Picture and Header Photo to Firebase

So I have a viewcontroller for a user to edit their profile picture and header photo. I have it to where the user selects a photo and it will save to firebase database and then will download the image and display it in the proper UIImage Views. Only problem I am having is that if I only edit the profile picture and hit save it saves both the profile picture and header photo even though I did not edit header photo. It also saves the data from the profile picture selected for both the profile picture and header photo which erases the original header photo and displaying the selected profile image in both UIImage Views. I'm not sure why it is doing this, I'm sure I am missing something important but I'm not sure what it is. Here is my entire viewcontroller for this.
import UIKit
import Foundation
import Firebase
import FirebaseDatabase
import FirebaseAuth
class NewEditProfileViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPickerViewDataSource, UIPickerViewDelegate {
#IBOutlet weak var imageView1: UIImageView!
#IBOutlet weak var imageView2: UIImageView!
#IBOutlet weak var usernameDisplay: UITextField!
#IBOutlet weak var artistBandDJ: UILabel!
#IBOutlet weak var editArtistBandDJ: UIButton!
let you = ["Artist", "Band", "DJ", "Musician", "Producer"]
var picker:UIPickerView!
var ref = DatabaseReference.init()
var imagePicker = UIImagePickerController()
var imagePicked = 0
var databaseRef = Database.database().reference()
var selectedImage1: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
guard let uid = Auth.auth().currentUser?.uid else { return }
self.databaseRef.child("users/profile").child(uid).observeSingleEvent(of: .value) { (snapshot:DataSnapshot) in
let dict = snapshot.value as? [String:Any]
self.usernameDisplay.text = dict!["username"] as? String
self.artistBandDJ.text = dict!["What do you consider yourself?"] as? String
if(dict!["photoURL"] != nil) {
let databaseProfilePic = dict!["photoURL"] as! String
if let data = NSData(contentsOf: NSURL(string: databaseProfilePic)! as URL) {
self.setProfilePic(imageView: self.imageView1,imageToSet:UIImage(data: data as Data)!)
}
}
if(dict!["headerURL"] != nil) {
let databaseHeaderPic = dict!["headerURL"] as! String
if let data2 = NSData(contentsOf: NSURL(string:databaseHeaderPic)! as URL) {
self.setHeaderPic(imageView2: self.imageView2, imageToSet2: UIImage(data: data2 as Data)!)
}
}
}
}
#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.saveHeaderPhoto()
self.savePicker()
self.saveUpdateName()
self.dismiss(animated: true, completion: nil)
}
#IBAction func backButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
func saveFIRData() {
guard let image = imageView1.image else { return }
self.uploadProfileImage(image){ url in
if url != nil {
self.saveProfileImage(profileURL: url!){ success in
if success != nil{
print("yes")
}
}
}
}
}
func saveHeaderPhoto() {
guard let image2 = imageView2.image else { return }
self.uploadHeaderImage(image2){ url in
self.saveHeaderImage(profileURL2: url!){ success in
if success != nil {
print("yes")
}
}
}
}
#IBAction func editButton(_ sender: Any) {
self.editButtonTapped()
}
func editButtonTapped() {
let vc = UIViewController()
vc.preferredContentSize = CGSize(width: 150, height: 150)
let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: 150, height: 150))
picker.delegate = self
picker.dataSource = self
vc.view.addSubview(picker)
let editBandDJAlert = UIAlertController(title: "What do you consider yourself?", message: nil, preferredStyle: UIAlertController.Style.alert)
editBandDJAlert.setValue(vc, forKey: "contentViewController")
editBandDJAlert.addAction(UIAlertAction(title: "Done", style: .default, handler: nil))
editBandDJAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(editBandDJAlert, animated:true)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return you.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return you[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
artistBandDJ.text = you[row]
}
internal func setProfilePic(imageView:UIImageView,imageToSet:UIImage) {
imageView1.layer.cornerRadius = imageView1.bounds.height / 2
imageView1.layer.masksToBounds = true
imageView1.image = imageToSet
}
internal func setHeaderPic(imageView2:UIImageView,imageToSet2:UIImage) {
imageView2.layer.masksToBounds = true
imageView2.image = imageToSet2
}
func savePicker() {
guard let uid = Auth.auth().currentUser?.uid else { return }
let selectedValue = artistBandDJ.text
let ref = Database.database().reference().root
let userObject = [
"What do you consider yourself?":selectedValue
]
ref.child("users/profile").child(uid).updateChildValues(userObject as [AnyHashable : Any])
}
func saveUpdateName() {
guard let uid = Auth.auth().currentUser?.uid else { return }
let updatedName = usernameDisplay.text
let ref = Database.database().reference().root
let userObject = [
"username":updatedName
]
ref.child("users/profile").child(uid).updateChildValues(userObject as [AnyHashable : Any])
}
}
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 for profile photo")
storageRef.downloadURL(completion: { (url, error) in
completion(url)
})
}else{
print("error in save image")
completion(nil)
}
}
}
func uploadHeaderImage(_ image2:UIImage, completion: #escaping (_ url2: URL?)->()) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let storageRef = Storage.storage().reference().child("users/\(uid)")
let imageData2 = imageView2.image?.jpegData(compressionQuality: 0.8)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
storageRef.putData(imageData2!, metadata: metaData) { (metaData, error) in
if error == nil{
print("success for header")
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/profile/\(uid)")
let userObject = [
"photoURL": profileURL.absoluteString
] as [String:Any]
self.ref.child("users/profile").child(uid).updateChildValues(userObject)
}
func saveHeaderImage(profileURL2:URL, completion: #escaping ((_ url: URL?) -> ())){
guard let uid = Auth.auth().currentUser?.uid else { return }
let databaseRef = Database.database().reference().child("users/profile/\(uid)")
let userObject = [
"headerURL": profileURL2.absoluteString
] as [String:Any]
self.ref.child("users/profile").child(uid).updateChildValues(userObject)
}
}
It looks like you're overriding everything when the users presses the save button. This could be solved by adding a property var headerChanged = false to the view controller. Then in chooseImage1 you set it to true.
When saveButton is called you check whether it has changed or not by checking the flag (headerChanged).

My chat data is successfully inserted into firebase, but I cannot fetch the data into designated chat rooms

I am currently following zero2launches chat application, and I also watched/completed their other tutorials on YouTube. While I started the chat application, I thought about changing the chat portion from a tableViewController to JSQMessageViewController. In that effort, I can post the data to firebase, but it won't show up in the individual chat rooms.
Here is the code:
var roomId: String!
var messages = [JSQMessage]()
func observeMessage() {
messageRef.observeEventType(.ChildAdded, withBlock: { snapshot in
//print(snapshot.value)
if let dict = snapshot.value as? [String: AnyObject] {
let mediaType = dict["MediaType"] as! String
let senderId = dict["senderId"] as! String
let senderName = dict["senderName"] as! String
switch mediaType {
case "TEXT":
let text = dict["text"] as? String
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, text: text))
case "PHOTO":
let fileUrl = dict["fileUrl"] as! String
let url = NSURL(string: fileUrl)
let data = NSData(contentsOfURL: url!)
let picture = UIImage(data: data!)
let photo = JSQPhotoMediaItem(image: picture)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: photo))
case "VIDEO":
let fileUrl = dict["fileUrl"] as! String
let video = NSURL(string: fileUrl)
let videoItem = JSQVideoMediaItem(fileURL: video, isReadyToPlay: true)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: videoItem))
default:
print("unknow data type")
}
if mediaType == "TEXT" {
let text = dict["text"] as? String
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, text: text))
}else if mediaType == "PHOTO" {
let fileUrl = dict["fileUrl"] as! String
let url = NSURL(string: fileUrl)
let data = NSData(contentsOfURL: url!)
let picture = UIImage(data: data!)
let photo = JSQPhotoMediaItem(image: picture)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: photo))
}else if mediaType == "VIDEO" {
let fileUrl = dict["fileUrl"] as! String
let video = NSURL(string: fileUrl)
let videoItem = JSQVideoMediaItem(fileURL: video, isReadyToPlay: true)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: videoItem))
}
print(dict)
let text = dict["text"] as? String
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, text: text))
self.collectionView.reloadData()
}
})
}
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: NSDate!) {
let newMessage = messageRef.childByAutoId()
let messageData = ["text": text, "senderId": senderId, "senderName": senderDisplayName, "MediaType": "TEXT"]
newMessage.setValue(messageData)
}
override func didPressAccessoryButton(sender: UIButton!) {
print("didPressAccessoryButton")
let sheet = UIAlertController(title: "Media Messages", message: "Please select a media", preferredStyle: UIAlertControllerStyle.ActionSheet)
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (alert:UIAlertAction) in
}
let photoLibrary = UIAlertAction(title: "Photo Library", style: UIAlertActionStyle.Default) { (alert: UIAlertAction) in
self.getMediaFrom(kUTTypeImage)
}
let videoLibrary = UIAlertAction(title: "Video Library", style: UIAlertActionStyle.Default) { (alert: UIAlertAction) in
self.getMediaFrom(kUTTypeMovie)
}
sheet.addAction(photoLibrary)
sheet.addAction(videoLibrary)
sheet.addAction(cancel)
self.presentViewController(sheet, animated: true, completion: nil)
}
func getMediaFrom(type: CFString) {
print(type)
let mediaPicker = UIImagePickerController()
mediaPicker.delegate = self
mediaPicker.mediaTypes = [type as String]
self.presentViewController(mediaPicker, animated: true, completion: nil)
}
override func collectionView(collectionView: JSQMessagesCollectionView!, messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
override func collectionView(collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let bubbleFactory = JSQMessagesBubbleImageFactory()
return bubbleFactory.outgoingMessagesBubbleImageWithColor(.blackColor())
}
override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("number of item:\(messages.count)" )
return messages.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! JSQMessagesCollectionViewCell
return cell
}
override func collectionView(collectionView: JSQMessagesCollectionView!, didTapMessageBubbleAtIndexPath indexPath: NSIndexPath!) {
print("didTapMessageBubbleAtIndexPath: \(indexPath.item)")
let message = messages[indexPath.item]
if message.isMediaMessage {
if let mediaItem = message.media as? JSQVideoMediaItem {
let player = AVPlayer(URL: mediaItem.fileURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.presentViewController(playerViewController, animated: true, completion: nil)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func sendMedia(picture: UIImage?, video: NSURL?) {
print(picture)
FIRStorage.storage().reference()
if let picture = picture {
let filePath = "\(FIRAuth.auth()?.currentUser!)\(NSDate.timeIntervalSinceReferenceDate())"
print(filePath)
let data = UIImageJPEGRepresentation(picture, 0.1)
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpg"
FIRStorage.storage().reference().child(filePath).putData(data!, metadata: metadata) { (metadata, error) in
if error != nil {
print(error?.localizedDescription)
return
}
let fileUrl = metadata!.downloadURLs![0].absoluteString
let newMessage = self.messageRef.childByAutoId()
let messageData = ["fileUrl": fileUrl, "senderId": self.senderId, "senderName": self.senderDisplayName, "MediaType": "PHOTO"]
newMessage.setValue(messageData)
}
}else if let video = video {
let filePath = "\(FIRAuth.auth()?.currentUser!)\(NSDate.timeIntervalSinceReferenceDate())"
print(filePath)
let data = NSData(contentsOfURL: video)
let metadata = FIRStorageMetadata()
metadata.contentType = "video/mp4"
FIRStorage.storage().reference().child(filePath).putData(data!, metadata: metadata) { (metadata, error) in
if error != nil {
print(error?.localizedDescription)
return
}
let fileUrl = metadata!.downloadURLs![0].absoluteString
let newMessage = self.messageRef.childByAutoId()
let messageData = ["fileUrl": fileUrl, "senderId": self.senderId, "senderName": self.senderDisplayName, "MediaType": "VIDEO"]
newMessage.setValue(messageData)
}
}
}
}
Here is my existing message database functions
let roofRef = FIRDatabase.database().reference()
class DataService {
static let dataService = DataService()
private var _BASE_REF = roofRef
private var _ROOM_REF = roofRef.child("captions")
private var _MESSAGE_REF = roofRef.child("messages")
private var _PEOPLE_REF = roofRef.child("people")
var currentUser: FIRUser? {
return FIRAuth.auth()!.currentUser!
}
var BASE_REF: FIRDatabaseReference {
return _BASE_REF
}
var ROOM_REF: FIRDatabaseReference {
return _ROOM_REF
}
var MESSAGE_REF: FIRDatabaseReference {
return _MESSAGE_REF
}
var PEOPLE_REF: FIRDatabaseReference {
return _PEOPLE_REF
}
var storageRef: FIRStorageReference {
return FIRStorage.storage().reference()
}
var fileUrl: String!
func CreateNewPost(user: FIRUser, caption: String, data: NSData) {
let filePath = "\(user.uid)/\(Int(NSDate.timeIntervalSinceReferenceDate()))"
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
storageRef.child(filePath).putData(data, metadata: metaData, completion: { (metadata, error) in
if let error = error{
print("Error uploarding: \(error.description)")
return
}
self.fileUrl = metadata!.downloadURLs![0].absoluteString
if let user = FIRAuth.auth()?.currentUser {
let idCaption = self.BASE_REF.child("captions").childByAutoId()
idCaption.setValue(["caption": caption, "thumbnailURLFromStorage": self.storageRef.child(metadata!.path!).description, "filelUrl": self.fileUrl])
}
})
}
func SignUp(username: String, email: String, password: String, data: NSData) {
FIRAuth.auth()?.createUserWithEmail(email, password: password, completion: { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
let changeRequest = user?.profileChangeRequest()
changeRequest?.displayName = username
changeRequest?.commitChangesWithCompletion({ (error) in
if let error = error {
print(error.localizedDescription)
return
}
})
let filePath = "profileImage/\(user!.uid)"
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpeg"
self.storageRef.child(filePath).putData(data, metadata: metadata, completion: { (metadata, error) in
if let error = error {
print("\(error.description)")
return
}
self.fileUrl = metadata?.downloadURLs![0].absoluteString
let changeRequestPhoto = user!.profileChangeRequest()
changeRequestPhoto.photoURL = NSURL(string: self.fileUrl)
changeRequestPhoto.commitChangesWithCompletion({ (error) in
if let error = error {
print(error.localizedDescription)
return
}else{
print("profile updated")
}
})
self.PEOPLE_REF.child((user?.uid)!).setValue(["username": username, "email": email, "profileImage": self.storageRef.child((metadata?.path)!).description])
ProgressHUD.showSuccess("Succeeded.")
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.login()
})
})
}
//implement login func
func login(email: String, password: String) {
FIRAuth.auth()?.signInWithEmail(email, password: password, completion: { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
ProgressHUD.showSuccess("Succeeded")
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.login()
})
}
// Update profile
func SaveProfile(username: String, email: String, data: NSData) {
let user = FIRAuth.auth()?.currentUser!
let filePath = "\(user!.uid)/\(Int(NSDate.timeIntervalSinceReferenceDate()))"
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
self.storageRef.child(filePath).putData(data, metadata: metaData) { (metaData, error) in
if let error = error {
print("Error uploading: \(error.description)")
return
}
self.fileUrl = metaData!.downloadURLs![0].absoluteString
let changeRequestProfile = user?.profileChangeRequest()
changeRequestProfile?.photoURL = NSURL(string: self.fileUrl)
changeRequestProfile?.displayName = username
changeRequestProfile?.commitChangesWithCompletion({ (error) in
if let error = error {
print(error.localizedDescription)
ProgressHUD.showError("NetWork error")
}else{
}
})
if let user = user {
user.updateEmail(email, completion: { (error) in
if let error = error {
print(error.description)
}else{
print("email update")
}
})
}
ProgressHUD.showSuccess("Saved")
}
}
func CreateNewMessage(userId: String, roomId: String, textMessage: String) {
let idMessage = roofRef.child("messages").childByAutoId()
DataService.dataService.MESSAGE_REF.child(idMessage.key).setValue(["message": textMessage, "senderId": userId])
DataService.dataService.ROOM_REF.child(roomId).child("messages").child(idMessage.key).setValue(true)
}
func fetchMessageFromServer(roomId: String, callback: (FIRDataSnapshot) -> ()) {
DataService.dataService.ROOM_REF.child(roomId).child("messages").observeEventType(.ChildAdded, withBlock: {snapshot -> Void in
DataService.dataService.MESSAGE_REF.child(snapshot.key).observeEventType(.Value, withBlock: {
snap -> Void in
callback(snap)
})
})
}