Getting tableview cell value nil in swift - swift

I have tableview with 3 sections. Every section has a row. In my simulator screen only 2 sections are showing . If I will scroll the table view the third cell will be shown. There is a save button, by clicking it I am passing data to another view controller. If I will not scroll the tableview and click the save button then the cell of third section is nil.
My code is:-
let indexPath = IndexPath(row: 0, section: 0)
let indexPath1 = IndexPath(row: 0, section: 1)
let indexPath2 = IndexPath(row: 0, section: 2)
let cell1 = tableView.cellForRow(at: indexPath) as? PatientInformationTableViewCell
let cell2 = tableView.cellForRow(at: indexPath1) as? PatientAdressTableViewCell
let cell3 = tableView.cellForRow(at: indexPath2) as? OtherInfoTableViewCell
guard let name = nameTextField.text,
let id = cell1.patientTextField.text,
let dob = cell1.dobTextField.text,
let street = cell1.streetAdressTextField.text,
let city = cell2.cityTextField.text,
let state = cell2.stateTextField.text,
let zip = cell2.zipTextField.text,
let country = cell2.CountryTextField.text,
let practioner = cell3.practionerTextField.text,
let lcode = cell3.lcodeTextField.text,
let qty = cell3.qtyTextField.text,
let prescription = cell3.PrescriptionTextView.text,
let klLevel = cell3.kLevelTextField.text,
let deviceType = cell3.deviceTypeTextField.text,
let guardian = cell3.guardianTextField.text,
let relationship = cell3.relationshipwithPatient.text
else {
return
}
let patient = PatientInformationModel(name: name, id: id, dob: dob, streetAdress: street, city: city, state: state, zip: zip, country: country, klevel: klLevel, deviceType: deviceType, visitType: "visitType", deliveryLocation: "deliveryLocation", lCode: lcode, qty: qty, descripePrescription: prescription, practioner: practioner, guardian: guardian, relationship: relationship)
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(patient) {
let defaults = UserDefaults.standard
defaults.set(encoded, forKey: "SavedPerson")
}
if let storyBoard = UIStoryboard(name: "Pdf", bundle: nil) as? UIStoryboard{
captureSignature { (sign) in
signatureImage = sign?.image
print("signature image is \(signatureImage)")
}
let PatientListViewController = storyBoard.instantiateViewController(identifier: "GeneratePdfViewController") as? GeneratePdfViewController
PatientListViewController?.signatureImage = signatureImage
self.navigationController?.pushViewController(PatientListViewController!, animated: true)
}
in this above code, if i am clicking on save button without scrolling to bottom , i am getting cell3 value nil.Is there any soution. please help me.

Related

Reloading tableView after liking a button in cell

My tableView shows some user comments loaded via Firebase Database. The tableView contains also a prototype cell. First of all loadPosts() gets executed. It loads every post and also goes to the user and takes the profile picture which is up to date and at last it sorts them after time.
Now the user has the option to like a post. In the extension UITableViewDelegate I created a cell.buttonAction. Here it opens into the users account and looks if he already liked the post with a specific id. If not it adds +1. If it did already it takes one -1.
The code itself works. But I have huge performance issues. Sometime the tableView gets updated immidiately. Sometimes I have to manually refresh it. As you can see right now I use observeSingleEvent. Should I better use observe instead? But then it crashes sometimes if someone posts and I have the same tableView opened. I also don't want it to reload every time the whole tableView if someone liked a post.
I also created a Video. Maybe it helps. I really do not know how I can solve that problem.
func loadPosts() {
let placeIdFromSearch = ViewController.placeidUebertragen
ref = Database.database().reference().child("placeID/\(placeIdFromSearch)")
ref.queryOrdered(byChild: "userTime").queryLimited(toLast: 10).observeSingleEvent(of: DataEventType.value, with: {(snapshot) in
self.table.removeAll()
for video in snapshot.children.allObjects as! [DataSnapshot] {
let Object = video.value as? [String: AnyObject]
let timestampDate = NSDate(timeIntervalSince1970: Double(Object?["userTime"] as! NSNumber)/1000)
...
let time = dateFormatter.string(from: timestampDate as Date)
...
let userTimeForArranging = Object?["userTime"]
ViewComments.commentIDNew = commentId as! String
getProfilePicture()
func getProfilePicture(){
self.ref = Database.database().reference()
self.ref.child("user/\(userID!)").observe (.value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let userImage = value?["picture"] as? String ?? ""
let userName = value?["firstname"] as? String ?? ""
let video = importComment(userName: userName as! String, userGroup: userGroup as! String, userComment: userComment as! String, userTime: userTime as! String, userLikes: userLikes as! Int, commentId: commentId as! String, placeID: placeID as! String, kommentarCount: kommentarCount as! Int, userImage: userImage as! String, userTimeForArranging: userTimeForArranging as! Int)
self.table.insert(video, at: 0)
self.table = self.table.sorted(by: { $0.userTimeForArranging! > $1.userTimeForArranging! })
self.tableView.reloadData()
})
}
}
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
let video: importComment
video = table[indexPath.row]
cell.layoutMargins = UIEdgeInsets.zero
...
cell.userImage.image = UIImage(url: URL(string: video.userImage!))
cell.buttonAction = {
getClickedRow(arg: true, completion: { (success) -> Void in
if success {
self.loadPosts()
} else {
}
})
func getClickedRow(arg: Bool, completion: #escaping (Bool) -> ()) {
let selectedIndexPath = self.table[indexPath.row].commentId!
ViewSubComments.subCommentIdNew = selectedIndexPath
completion(arg)
}
}
return cell
}
From Prototype cell:
#IBAction func buttonTapped(_ sender: UIButton) {
buttonAction?()
let ref = Database.database().reference()
let userID = Auth.auth().currentUser!.uid
ref.child("user/\(userID)/places/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
getLikeAndMinusOne ()
let database = Database.database().reference()
database.child("user/\(userID)/places/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").removeValue()
}else{
getLikeAndAddOne ()
let database = Database.database().reference()
let object: [String: Any] = [
"like": "true",]
database.child("user/\(userID)/places/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").setValue(object)
}
})
func getLikeAndAddOne () {
let database = Database.database().reference()
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").observeSingleEvent(of: .value, with: { (snapshot) in
let userDict = snapshot.value as! [String: Any]
let userLikes = userDict["userLikes"] as! Int
var userLikesNeu = Int(userLikes)
userLikesNeu = Int(userLikes) + 1
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").updateChildValues(["userLikes": userLikesNeu])
})}
func getLikeAndMinusOne () {
let database = Database.database().reference()
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").observeSingleEvent(of: .value, with: { (snapshot) in
let userDict = snapshot.value as! [String: Any]
let userLikes = userDict["userLikes"] as! Int
var userLikesNeu = Int(userLikes)
userLikesNeu = Int(userLikes) - 1
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").updateChildValues(["userLikes": userLikesNeu])
})}
}

NavigationController unable to show back button in Detailed View Controller when Search Controller is active

I have a UITableView with a search controller, when the search controller is active and cell is selected it passes the data to a detailed view controller.
All the data is passed, but there is no back navigation button present on the top left, if the search controller is inactive and the cell is selected the back navigation button is present, and it brings it back to the search and works perfectly for that scenario.
Here's the code for didSelectRowAt:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "PostTableDetailed") as! PostTableDetailed
var user = usersArray[indexPath.row]
if(self.searchController.isActive) {
user = filteredUsers[indexPath.row]
let title = user?.value(forKey: "title")
print(title)
DvC.getName = title as! String
let image = user?.value(forKey: "image")
print(image)
DvC.getImg = image as! String
let desc = user?.value(forKey: "description")
print(desc)
DvC.getDesc = desc as! String
var contact = user?.value(forKey: "contact")
print(contact)
if contact == nil {
contact = ""
} else {
DvC.getContact = contact as! String
}
let address = user?.value(forKey: "address")
print(address)
DvC.getAddress = address as! String
self.navigationController?.pushViewController(DvC, animated: true)
}
else {
user = usersArray[indexPath.row]
print(user!)
let title = user?.value(forKey: "title")
print(title)
DvC.getName = title as! String
let image = user?.value(forKey: "image")
print(image)
DvC.getImg = image as! String
let desc = user?.value(forKey: "description")
print(desc)
DvC.getDesc = desc as! String
var contact = user?.value(forKey: "contact")
print(contact)
if contact == nil {
contact = ""
} else {
DvC.getContact = contact as! String
}
let address = user?.value(forKey: "address")
print(address)
DvC.getAddress = address as! String
self.navigationController?.pushViewController(DvC, animated: true)
}
}
Please check for if you have added two navigation controllers Or might be you are hiding back button.
try to add UISearchBar as navigation title view in navigation bar

How can firebase users be displayed/ranked according to their distance away from each other with CLLocation?

The page should list all users in the firebase database who are within 3 miles. Right now it just lists all the users. In addition to limiting the listing of users to those within 3 miles, it would be good to rank the displayed users, from closest to furthest.
Below is code that already works to display all the users (within 3 miles and further) from the firebase database. All users have a location in firebase - latitude and longitude.
for people in snapshot.children.allObjects as! [DataSnapshot] {
if people.key != thisUsersUid { //do not add this users info to the array
let peopleObject = people.value as? [String: AnyObject]
let peopleEducation = peopleObject?["Education"] as? String
let peopleWhatIamConsideringBuying = peopleObject?["WhatIamConsideringBuying"] as? String
let peoplePhotoPosts = peopleObject?["PhotoPosts"] as? String
let peopleimageDownloadURL = peopleObject?["imageDownloadURL"] as? String
let peoplepostID = peopleObject?["postID"] as? String
let peoplepeopleWhoLike = peopleObject?["peopleWhoLike"] as? String
let peopl = Userx(Education: peopleEducation, WhatIamConsideringBuying: peopleWhatIamConsideringBuying, PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL, postID: peoplepostID, peopleWhoLike: peoplepeopleWhoLike)
self.people.append(peopl)
}
self.table.reloadData()
}
}
})
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let immy = cell.viewWithTag(1) as! UIImageView
let person: Userx = people[indexPath.row]
cell.lblName.text = person.Education
cell.postID = self.people[indexPath.row].postID
if let PhotoPosts = person.PhotoPosts {
let url = URL(string: PhotoPosts)
immy.sd_setImage(with: url)
}
return cell
}
/Below makes the users locations:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
print("locations = \(locValue.latitude) \(locValue.longitude)")
latestLocation = ["latitude" : locValue.latitude, "longitude" : locValue.longitude]
if let locationDictionary = latestLocation {
databaseRef.child("people").child(uid).child("Coordinates").setValue(locationDictionary)
}
//Update after answer:
for people in snapshot.children.allObjects as! [DataSnapshot] {
.......
let peoplepeopleWhoLike = peopleObject?["peopleWhoLike"] as? String
let userId = people.key
let coordSnap = people.childSnapshot(forPath: "Coordinates")
let lat = coordSnap.childSnapshot(forPath: "latitude").value as! CLLocationDegrees
let lon = coordSnap.childSnapshot(forPath: "longitude").value as! CLLocationDegrees
let locCoord = CLLocationCoordinate2DMake(lat, lon)
let coordinates = CLLocationCoordinate2D(latitude: lat, longitude: lon)
let peopleLocation = (lat, lon)
print(userId, "coords: \(lat) \(lon)")
let distance = peopleLocation.distance(to: latestLocation)
let peopl = Userx(Education: peopleEducation, WhatIamConsideringBuying: peopleWhatIamConsideringBuying, PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL, postID: peoplepostID, peopleWhoLike: peoplepeopleWhoLike, distance: distance)
Right Now: All users randomly displayed below each other.
What I need: Users within 3 miles displayed underneath each other, from closest to furthest.
First of all, you need to have the distance of the retrieved users from Firebase, meaning you need to get the object "Coordinates" and store the distance from the current user inside Userx.
Then you'd do something like this:
for people in snapshot.children.allObjects as! [DataSnapshot] {
if people.key != thisUsersUid { //do not add this users info to the array
let peopleObject = people.value as? [String: AnyObject]
let peopleEducation = peopleObject?["Education"] as? String
let peopleWhatIamConsideringBuying = peopleObject?["WhatIamConsideringBuying"] as? String
let peoplePhotoPosts = peopleObject?["PhotoPosts"] as? String
let peopleimageDownloadURL = peopleObject?["imageDownloadURL"] as? String
let peoplepostID = peopleObject?["postID"] as? String
let peoplepeopleWhoLike = peopleObject?["peopleWhoLike"] as? String
let peopleLocation = ... // Map user location here using CLLocation(latitude: Double, longitude: Double)
let distance = peopleLocation.distance(to: thisUserLocation) // thisUserLocation is the one you're getting in latestLocation
let peopl = Userx(Education: peopleEducation, WhatIamConsideringBuying: peopleWhatIamConsideringBuying, PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL, postID: peoplepostID, peopleWhoLike: peoplepeopleWhoLike, distance: distance)
self.people.append(peopl)
}
people.sort(by: { (p1, p2) -> Bool in
return p1.distance < p2.distance
})
self.table.reloadData()
}

How to Firebase retrieve data below UID and auto ID In Swift

[enter image description here][1]I'm trying to retrieve specific data from Database. I'd like to read all data in product_list
My Database
This is what i try but when i print listName. It show like this listName = nil
let refList = Database.database().reference().child("Users/Sellers")
refList.observe(DataEventType.value, with:{(snapshot) in
if snapshot.childrenCount>0{
self.listProduct.removeAll()
for lists in snapshot.children.allObjects as! [DataSnapshot]{
let userList = lists.value as? [String: AnyObject]
let listName = userList?["name"]
let listDetail = userList?["detail"]
let listPrice = userList?["price"]
print("key = \(listName)")
let list = ListModel(name: listName as! String?, detail: listDetail as! String?, price: listPrice as! String?)
self.listProduct.append(list)
}
self.tableList.reloadData()
}
})
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let list: ListModel
list = listProduct[indexPath.row]
cell.lblName.text = list.name
cell.lblDetail.text = list.detail
cell.lblPrice.text = list.price
return cell
}
It have 4 things i want to retrieve
(details, name, price and product_image_url)
Right now your code is looping over the child nodes of /Users/Sellers, which is the nodes of each individual user. What you seem to want to do is include all nodes under the product_list property of each user, which requires an extra nested loop:
let refList = Database.database().reference().child("Users/Sellers")
refList.observe(DataEventType.value, with:{(snapshot) in
if snapshot.childrenCount>0{
self.listProduct.removeAll()
for user in snapshot.children.allObjects as! [DataSnapshot]{
let productList = user.childSnapshot(forPath: "product_list")
for product in productList.children.allObjects as! [DataSnapshot]{
let userList = product.value as? [String: AnyObject]
let listName = userList?["name"]
let listDetail = userList?["details"] // NOTE: also fixed a typo here
let listPrice = userList?["price"]
print("key = \(listName)")
let list = ListModel(name: listName as! String?, detail: listDetail as! String?, price: listPrice as! String?)
self.listProduct.append(list)
}
}
self.tableList.reloadData()
}
})

UISearchBar and Firebase Database

struct postStruct {
let title : String!
let author : String!
let bookRefCode : String!
let imageDownloadString : String!
let status : String!
let reserved : String!
let category : String!
let dueDate : String!
}
'Above is where i set up the structure for the post, and below, is how i reference and retrieve the data from the firebase database.
My problem is that when you set up the searcher, i do not know how to get it to search based off of the title of the post.'
class DirectoryTableView: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
let databaseRef = Database.database().reference()
databaseRef.child("Books").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
var snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
snapshotValue = snapshot.value as? NSDictionary
let author = snapshotValue!["author"] as? String
snapshotValue = snapshot.value as? NSDictionary
let bookRefCode = snapshotValue!["bookRefCode"] as? String
snapshotValue = snapshot.value as? NSDictionary
let status = snapshotValue!["status"] as? String
snapshotValue = snapshot.value as? NSDictionary
let reserved = snapshotValue!["reserved"] as? String
snapshotValue = snapshot.value as? NSDictionary
let category = snapshotValue!["category"] as? String
snapshotValue = snapshot.value as? NSDictionary
let dueDate = snapshotValue!["dueDate"] as? String
snapshotValue = snapshot.value as? NSDictionary
self.posts.insert(postStruct(title: title, author: author, bookRefCode: bookRefCode, status: status, reserved: reserved, category: category, dueDate: dueDate) , at: 0)
self.tableView.reloadData()
})
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let databaseRef = Database.database().reference()
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].title
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].author
let label3 = cell?.viewWithTag(3) as! UILabel
label3.text = posts[indexPath.row].bookRefCode
let label4 = cell?.viewWithTag(4) as! UILabel
label4.text = posts[indexPath.row].status
let label5 = cell?.viewWithTag(5) as! UILabel
label5.text = posts[indexPath.row].category
let image1 = cell?.viewWithTag(6) as! UILabel
image1.text = posts[indexPath.row].imageDownloadString
let label6 = cell?.viewWithTag(7) as! UILabel
label6.text = posts[indexPath.row].reserved
let label9 = cell?.viewWithTag(9) as! UILabel
label9.text = posts[indexPath.row].dueDate
return cell!
}
'Also, does anyone know how to sort the tableview cells (posts in this case) alphabetically?'
You can get all data already ordered alphabetically
databaseRef.child("Books").queryOrdered(byChild: "title").observe(.childAdded, with: { snapshot in
var snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
snapshotValue = snapshot.value as? NSDictionary
....
}
or sort your array before reload the tableView
var sortedArray = swiftArray.sorted { $0.title.localizedCaseInsensitiveCompare($1.title) == ComparisonResult.orderedAscending }
Sample structure
for sorting data according to searchBar I had used an dictionary that having all my snapshot and I compared my searchBar text in that dict and after sorting reloaded tableView here is code that you can have a look at
//method to get all user Details in a dict
func getEmail() {
let databaseRef = Database.database().reference().child("users")
databaseRef.observe(.value, with: { (snapshot) in
if snapshot.exists(){
self.postData = snapshot.value as! [String : AnyObject]
let dictValues = [AnyObject](self.postData.values)
self.sarchDict = dictValues
}
})
}
//search bar delegate
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if self.mySearchBar.text!.isEmpty {
// set searching false
self.isSearching = false
}else{
// set searghing true
self.isSearching = true
self.names.removeAll()
self.uidArray.removeAll()
self.imageUrl.removeAll()
for key in self.sarchDict {
let mainKey = key
//I am making query against email in snapshot dict
let str = key["email"] as? String
//taking value of email from my dict lowerCased to make query as case insensitive
let lowercaseString = str?.lowercased()
//checking do my any email have entered letter or not
if(lowercaseString?.hasPrefix(self.mySearchBar.text!.lowercased()))!{
//here I have a check so to remove value of current logged user
if ((key["uID"] as! String) != (Auth.auth().currentUser?.uid)!){
//If value is found append it in some arrays
self.imageUrl.append( key["profilePic"] as! String )
self.names.append( key["name"] as! String )
self.uidArray.append( key["uID"] as! String )
//you can check which values are being added from which key
print(mainKey)
}
}
}
//reload TableView here
}
}
//TableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell = self.myTableView.dequeueReusableCell(withIdentifier: "Cell")!
if self.isSearching == true {
let imageView = (cell.viewWithTag(1) as! UIImageView)
imageView.setRounded()
if imageUrl[indexPath.row] != "" {
self.lazyImage.showWithSpinner(imageView:imageView, url:imageUrl[indexPath.row])
}
else{
imageView.image = UIImage(named: "anonymous")
}
(cell.contentView.viewWithTag(2) as! UILabel).text = self.names[indexPath.row]
}
else {
}
return cell
}
I'm sure this will be helpful to some using FireStore. Here I'm just setting my reference to point to the right collection. "name" is my field I wish to search by and is greater than will be checked chronologically on my string. The further they type the more defined the search results are.
static func searchForProgramStartingWith(string: String) {
let programsRef = db.collection("programs")
programsRef.whereField("name", isGreaterThan: string).limit(to: 10).getDocuments { (snapshot, error) in
if error != nil {
print("there was an error")
} else {
let shots = snapshot?.documents
for each in shots! {
let data = each.data()
let name = data["name"]
print("The name is \(name!)")
}
}
}
}