im trying to fetch data from firestore for certain user and what i mean here is if there is a user his name is Mark and he logged in to his account i want to fetch MarkCollection from the Firestore so i decided to use if statement but it doesn't work . here in the first example i can fetch the data but i want this data to be displayed for the user Mark only and in the second Example i used if statement but the problem is loadData1() cannot execute inside if statement.
First Example:
import UIKit
import FirebaseFirestore
import Firebase
import FirebaseAuth
class orderTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var userName: UITextField!
var db: Firestore!
var phone = [String]()
var reciept = [String]()
var price = [String]()
var amount = [String]()
var Area = [String]()
override func viewDidLoad() {
super.viewDidLoad()
loadData1()
}
func loadData1() {
db.collection("markCollection").getDocuments() {
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
for document in querySnapshot!.documents {
self.Area.append(document.get("area") as? String ?? "")
self.phone.append(document.get("phone") as? String ?? "")
self.reciept.append(document.get("reciept") as? String ?? "")
self.price.append(document.get("total price") as? String ?? "")
self.amount.append(document.get("amount") as? String ?? "")
}
}
self.order.reloadData()
}
}
}
and here is the problem when i use the if statement , the loadData1() func cannot execute
here is the code for Example 2:
import UIKit
import FirebaseFirestore
import Firebase
import FirebaseAuth
class orderTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var userName: UITextField!
var db: Firestore!
var phone = [String]()
var reciept = [String]()
var price = [String]()
var amount = [String]()
var Area = [String]()
override func viewDidLoad() {
super.viewDidLoad()
if userName.text == "Mark" {
loadData1()
}
}
func loadData1() {
db.collection("markCollection").getDocuments() {
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
for document in querySnapshot!.documents {
self.Area.append(document.get("area") as? String ?? "")
self.phone.append(document.get("phone") as? String ?? "")
self.reciept.append(document.get("reciept") as? String ?? "")
self.price.append(document.get("total price") as? String ?? "")
self.amount.append(document.get("amount") as? String ?? "")
}
}
self.order.reloadData()
}
}
}
[1]
[1]: https://i.stack.imgur.com/5YONj.png
if you do not set a text "Mark" as a default text to the textField, it is nil at the moment that view cycle is in "ViewDidLoad". When a user enters something by using the keyboard, it happens in a different cycle.
You should check if userName.text == "Mark" when the user taps "done" button in the keyboard, or by checking in TextFields delegates while the user is typing.
to check the user input;
you can add this in viewDidLoad;
userName.addTarget(self, action: #selector(textFieldDidChange(_:)),
for: .editingChanged)
and then, in view controller;
#objc private func textFieldDidChange(_ textField: UITextField) {
print(textField.text) // so that you can see whether you can successfully connect the outlet. if nothing prints, it means that you could not connect it properly.
if textField.text = "Mark" {
loadData1()
}
}
Related
Im trying to get document for each user login to his account , i have two collections in Firestore one called ( firstName ) and the second one called ( lastName ) and i want from user 1 to get ( firstName ) collection only and user number 2 to get ( lastName ) collection only.
i tried with if statement but it doesn't work with me .
import UIKit
import FirebaseFirestore
import Firebase
import FirebaseAuth
class namesTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var names: UITableView!
var db: Firestore!
var firstName = [String]()
var lastName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
names.register(UINib(nibName: "Order1TableViewCell", bundle: nil) , forCellReuseIdentifier: "order")
names.dataSource = self
names.delegate = self
db = Firestore.firestore()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let viewController1 = storyboard.instantiateViewController(withIdentifier: "login") as? logInViewController else{return}
viewController1.userNameField?.delegate = self
if viewController1.userNameField?.text == “1#1.com" {
loadData1()
}
if viewController1.userNameField?.text == “2#2.com” {
loadData2()
}
func loadData1() {
db.collection("firstName").getDocuments()
{
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
for document in querySnapshot!.documents {
self.firstName.append(document.get("firstname") as? String ?? "")
self.lastName.append(document.get("lastname") as? String ?? "")
}
}
self.names.reloadData()
}
}
func loadData2() {
db.collection("lastName").getDocuments()
{
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
for document in querySnapshot!.documents {
self.firstName.append(document.get("firstname") as? String ?? "")
self.lastName.append(document.get("lastname") as? String ?? "")
}
}
self.names.reloadData()
}
}
}
this is logInViewController code
import UIKit
import Firebase
import FirebaseAuth
class logInViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var userNameField: UITextField!
#IBOutlet var passwordField: UITextField!
#IBOutlet var logInButton: UIButton!
override func viewDidLoad() {
logInButton.layer.cornerRadius = 4.0
super.viewDidLoad()
userNameField.delegate = self
passwordField.delegate = self
// Do any additional setup after loading the view.
}
#IBAction func logInButtonClicked(_ sender: Any) {
Auth.auth().signIn(withEmail: (userNameField.text ?? ""), password: (passwordField.text ?? "")) { (result, error) in
if let _eror = error{
let alert = UIAlertController(title: "Error", message: error!.localizedDescription, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okAction)
self.present(alert,animated: true)
print(_eror.localizedDescription)
}else{
if let _res = result{
print(_res)
}
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "order1") as! namesTableViewController
self.navigationController!.pushViewController(VC1, animated: true)
}
}
}
}
this is fire store structure
image
Be careful by doing let view1 = firstViewController() you are not grabbing the correct instance of firstViewController but one you just created. User.text therefore won't be set. You need to grab the right instance of it, if you are using storyboard you can do:
let storyboard = UIStoryboard(name: "nameofstoryboard", bundle: nil)
guard let viewController1 = storyboard.instantiateViewController(withIdentifier: "myIdentifier") as? firstViewController else{return} //set VC Identifier in Storyboard identity inspector
Then you can check the User property with if-statement
I'm hoping someone can help me understand how to get the value from an array rather than all system information about the array as shown via screen shot below.
I would instead prefer just "test" to show to prove that CoreData saved and returned the value.
Here is the code:
import UIKit
import CoreData
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newItem = Item(context: context)
var textIn = ""
var textOut = ""
var itemArray = [] as Array
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var dataIn: UITextField!
#IBAction func save(_ sender: Any) {
newItem.title = dataIn.text
saveItems()
}
#IBOutlet weak var textLabel: UILabel!
#IBAction func showButton(_ sender: Any) {
loadItems()
}
func saveItems() {
do {
try context.save()
print("Saved!")
} catch {
print("Error saving context \(error)")
}
}
func loadItems() {
let request : NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request) as [Any]
for item in itemArray {
print(item.self)
textLabel.text = ("Value: \(item.self)")
}
} catch {
print("Error fetching data from context \(error)")
}
}
}
Thanks!
Rather than the worst type [Any] use the best type [Item]
var itemArray = [Item]()
Then remove the pointless type cast in loadItems to be able to use the title attribute
func loadItems() {
let request : NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request)
for item in itemArray {
print(item.title)
textLabel.text = ("Value:", item.title)
}
} catch {
print("Error fetching data from context \(error)")
}
}
Consider that after the loop the label will display always the title of the last item in the array.
Currently I am attempting to push values into an array of note objects from firebase
The only issue is due to Firebases asynchronous nature, I am having trouble getting the main thread to wait until the fetch function is completed. I have viewed many answers on this site and I have read up on the Semaphores and Dispatch queue documentation however I cannot get this fetch to work. It appears that most of the people here are attempting to use a table view which I am not.
Here is the fetch code
func fetchUser(){
FIRDatabase.database().reference().child("notes").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = noteClass(dictionary: dictionary)
self.coordinotes.append(user)
}
}, withCancel: nil)
}
I have removed all of my semaphore and dispatch main attempts due to none of them working. This function is called in my view did load. When i check the values of my array that i push them into 'coordinotes' the value is not yet placed in and i get an out of bounds error.
Rest of code
import UIKit
import MapKit
import CoreLocation
import Firebase
import FirebaseDatabase
struct PreferencesKeys{
static let savedItems = "savedItems"
}
class ViewController: UIViewController, CLLocationManagerDelegate{
let manager = CLLocationManager()
var coordinotes:[noteClass] = Array()
var latitude = Double()
var noteTime = noteBrain()
//Map
#IBOutlet weak var map: MKMapView!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations[0]
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, noteTime.span)
map.setRegion(region, animated: true)
self.map.showsUserLocation = true
}
override func viewDidLoad()
{
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleLogout))
if FIRAuth.auth()?.currentUser?.uid == nil {
perform(#selector(handleLogout), with: nil, afterDelay: 0)
}
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
fetchUser()
loadAllCoordinotes()
}
func handleLogout() {
do {
try FIRAuth.auth()?.signOut()
} catch let logoutError {
print(logoutError)
}
let loginController = LoginController()
present(loginController, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loadAllCoordinotes() {
let length = coordinotes.count - 1
map.addAnnotation(coordinotes[length])
}
func fetchUser(_ completion:#escaping ([noteClass] , _ success: Bool)-> Void){
let coordinotes = [noteClass]()
FIRDatabase.database().reference().child("notes").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = noteClass(dictionary: dictionary)
coordinotes.append(user)
}
completion(coordinotes, true)
}, withCancel: nil)
}
and then you call it in viewDidLoad like this:
fetchUser { (coordinotes, success) in
if success {
self.coordinotes = coordinote
self.loadAllCoordinotes()
}
}
My swift code below uses UITextFieldDelegate in textfield var enterT. nameString converts a core data entity to the array of strings, like [bob,bryan,jessica]. In textFieldDidEndEditing, I want the user to be able to enter any number, e.g 3 and third element from the array to be printed and then sort the array.
import UIKit
import CoreData
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var labelName : UILabel!
#IBOutlet var enterT : UITextField!
let appDelegate = UIApplication.shared.delegate as! AppDelegate //Singlton instance
var context:NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
openDatabse()
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard let index = Int(textField.text!) else {
// display an alert about invalid text
return
}
joke(at: index)
}
func joke(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
print(user.username)
}
} catch {
print("Could not fetch \(error) ")
}
}
func openDatabse()
{
context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Users", in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
let newUser2 = NSManagedObject(entity: entity!, insertInto: context)
let newUser3 = NSManagedObject(entity: entity!, insertInto: context)
saveData(UserDBObj: newUser, UserDBObj2: newUser2, UserDBObj3: newUser3)
}
func saveData(UserDBObj:NSManagedObject,UserDBObj2:NSManagedObject,UserDBObj3:NSManagedObject)
{
UserDBObj.setValue("kim kardashian", forKey: "username")
UserDBObj2.setValue("jessica biel", forKey: "username")
UserDBObj3.setValue("Hailey Rienhart", forKey: "username")
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed")
}
fetchData()
}
func fetchData()
{
print("Fetching Data..")
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
let userName = data.value(forKey: "username") as! String
print("User Name is : "+userName)
}
} catch {
print("Fetching data Failed")
}
}}
Convert the entered number to Int. If this succeeds pass the integer to joke and fetch the record matching the idx attribute.
Consider that indexes start with zero. If you want to enter numbers starting with one you have to decrement the index (joke(at: index - 1))
#IBOutlet var enterT : UITextField!
func textFieldDidEndEditing(_ textField: UITextField) {
guard let index = Int(textField.text!) else {
// display an alert about invalid text
return
}
joke(at: index)
}
func joke(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
print(user.username)
}
} catch {
print("Could not fetch \(error) ")
}
}
Note: I recommend to define idx and username as non-optional in the Core Data model. And make sure that all idx values are unique.
I'm trying to download user from Firebase and save them in an array using a Usermodel.
The download works so far, but how do I access the first user and show the picture of this user?
My Usermodel: Sorry for some German words
class UserModel {
var username: String?
var email: String?
var profilImageUrl: String
var birthdayDate: String?
var gender: String?
var userDescription: String?
init(dictionary: [String: Any]) {
username = dictionary["username"] as? String
email = dictionary["email"] as? String
profilImageUrl = dictionary["profilImageURL"] as? String ?? ""
birthdayDate = dictionary["Geburtsdatum"] as? String
gender = dictionary["gender"] as? String
userDescription = dictionary["description"] as? String
}
In the following I´m saving the downloaded Data to the array "attendees".The picture of the first user in this array should be shown in firstUserImageView.
import SDWebImage
var attendees = [UserModel]()
#IBOutlet weak var firstUserImageView: UIImageView!
//load attendees with Api -> that works.
print(attendees.count) gives me the amount of attendees saved in the database
func loadAttendees(){
guard let eventID = event?.id else {return}
AttendeeApi.shared.observeEventAttendee(eventID: eventID) { (attendeeId) in
AttendeeApi.shared.observeAttendee(attendeeId: attendeeId, completion: { (attendee) in
self.attendees.append(attendee)
})
}
}
Set up the image view
var attendee: UserModel?{
didSet {
let firstAttendee = attendees[0].profilImageUrl
guard let firstUserImageUrl = URL(string: firstAttendee) else {return}
firstUserImageView.sd_setImage(with: firstUserImageUrl) { (_, _, _, _) in
}
}
}
loadAttendees is called in viewDidLoad but the ImageView does not show the picture of the first user.
var REF_ATTENDEE = Database.database().reference().child("users")
func observeAttendee (attendeeId: String, completion: #escaping (UserModel) -> Void) {
REF_ATTENDEE.child(attendeeId).observeSingleEvent(of: .value) { (snapshot) in
guard let dic = snapshot.value as? [String: Any] else {return}
let newAttendee = UserModel(dictionary: dic)
completion(newAttendee)
}
}
var REF_EVENTS_ATTENDEES = Database.database().reference().child("events - attendees")
func observeEventAttendee(eventID: String, completion: #escaping (String) -> Void) {
REF_EVENTS_ATTENDEES.child(eventID).observe(.childAdded) { (snapshot) in
let attendeeId = snapshot.key
completion(attendeeId)
}
}