I'm in trouble with retrieving data from Firebase.
My JSON looks like this:
-user
-contacts
-autoID Value1
-contactName : A
-autoID Value2
-contactName : B
-autoID Value3
-contactName : C
(more contactName is coming, in same structure.)
But I have no idea how to get ALL contactName's Data(A,B,C....) then print in UITableView in Swift3.0
I want to make a result like this :
#In the TableView#
A
B
C
...
But My result is different, Maybe some problem in TableViewCell.swift... but I'm not sure
ViewController.swift :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MoneyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MoneyTableViewCell", for: indexPath) as! MoneyTableViewCell
cell.eachCell()
cell.layoutIfNeeded()
return cell
}
MoneyTableViewCell.swift
func eachCell() {
dbRef = Database.database().reference()
self.dbRef.child("user/contacts").observe(.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
let receiverNameDB = child.childSnapshot(forPath: "contactName").value! as! String
self.nameArray.append(receiverNameDB)
self.nameLabel.text = receiverNameDB
print(self.nameArray)
continue
}
}
})
}
Can Anybody help me please ;)
Update - I solved this problem! Here is my edited code...
Thanks to #Abdul91
The problem was.. I had to get the data from DB first, then put them in the array. After that get each data for tableView.
My edited code will tell you more.
ViewController.swift:
var nameArray:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
getNameDB{ value in
self.nameArray = value
self.tableView.reloadData()
}
tableView.register(UINib(nibName: "MoneyTableViewCell", bundle: nil), forCellReuseIdentifier: "MoneyTableViewCell")
}
//completion is for getting DB value outside of block..
func getNameDB(completion: #escaping (_ value: [String]) -> Void) {
self.dbRef.child("user/contacts").observe(.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
let receiverNameDB = child.childSnapshot(forPath: "contactName").value! as! String
self.nameArray.append(receiverNameDB)
}
completion(self.nameArray)
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.nameArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MoneyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MoneyTableViewCell", for: indexPath) as! MoneyTableViewCell
cell.nameLabel.text = nameArray[(indexPath as NSIndexPath).row]
cell.layoutIfNeeded()
return cell
}
Related
I want to create a tableview that has two custom cells in it, with the information being pulled from Firebase Database. The first custom cell displays the dates, and the second custom cell displays the events. When I run the app, the tableview is only returning the first custom cell, which is the dates. What would be causing this?
import UIKit
import Firebase
class augustController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var augustController: UITableView!
var ref = DatabaseReference()
var date = [String]()
var event = [String]()
var databaseHandle:DatabaseHandle = 0
var databaseHandle2:DatabaseHandle = 0
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
databaseHandle = ref.child("Events").child("August").child("dates").observe(.childAdded) { (snapshot) in
let post = snapshot.value as? String
if let actualPost = post {
self.date.append(actualPost)
}
}
databaseHandle2 = ref.child("Events").child("August").child("events").observe(.childAdded) { (snapshot) in
let post2 = snapshot.value as? String
if let actualPost2 = post2 {
self.event.append(actualPost2)
self.augustController.reloadData()
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return date.count
}
func tableView2(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return event.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let augustDate = tableView.dequeueReusableCell(withIdentifier: "augustDate") as! dateCell
augustDate.date.text = date[indexPath.row]
return(augustDate)
}
func tableView2(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let augustEvents = tableView.dequeueReusableCell(withIdentifier: "augustEvents") as! eventCell
augustEvents.even.text = event[indexPath.row]
return(augustEvents)
}
}
You implement cellForRow twice , you have to
var itemsArr = [Item]()
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = itemsArr[indexPath.row]
if item.isDate {
let augustDate = tableView.dequeueReusableCell(withIdentifier: "augustDate") as! dateCell
augustDate.date.text = item.content
return augustDate
}
else {
let augustEvents = tableView.dequeueReusableCell(withIdentifier: "augustEvents") as! eventCell
augustEvents.even.text = item.content
return augustEvents
}
}
//
then make it one array and append items of this struct type
struct Item {
var isDate:Bool
var content:String
}
I have an array of dictionary saved in User Defaults. I am showing these value in UITableview. When the user right swipes the table cell and remove it, the cell is successfully deleted, but it is not actually deleted from User Defaults.Here what I tried :
var notificationArray: [[String: AnyObject]] = []
var title = [String]()
var detail = [String]()
override func viewDidLoad() {
super.viewDidLoad()
if let tempArray = UserDefaults().array(forKey: "notificationArray") as? [[String: AnyObject]] {
notificationArray = tempArray
self.title = tempArray.flatMap { $0["title"] as? String }
self.detail = tempArray.flatMap { $0["detail"] as? String }
}
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.title.remove(at: indexPath.row)
self.detail.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
notificationArray.append(["title": title as AnyObject, "detail": detail as AnyObject])
UserDefaults.standard.set(notificationArray, forKey: "notificationArray")
print("title, detail", title, detail)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return title.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 80
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : SubCategoryTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SubCategoryTableViewCell
cell.notificationTittleLabel.text = title[indexPath.row]
cell.notificationDetailLabel.text = detail[indexPath.row]
cell.backgroundColor = UIColor.clear
return cell
}
This is worked for me. Thanks, #Paulw11 :)
var myNotificationArray = UserDefaults.standard.object(forKey: "notificationArray") as? [AnyHashable]
myNotificationArray?.remove(at: indexPath.row)
UserDefaults.standard.set(myNotificationArray, forKey: "notificationArray")
UserDefaults.standard.synchronize()
I am fetching data from Core Data, the returned data is correct when printed in the console. But the tableview always returns empty cells. The object exists, numberOfRowsinSection is returned with the proper count as well.
Been looking for hours, I hope its not a typo. Any help is appreciated, the code is below. I tried both valueForKey and valueForKeypath with no success
Thanks!
import UIKit
import CoreData
class HistoryViewController: UITableViewController{
#IBOutlet var historyTableView: UITableView!
var activitiesHistory: [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "Past Workouts"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "historyCell")
let entity = NSEntityDescription.entity(forEntityName: "Activity", in: CoreDataStack.context)
let fetchRequest: NSFetchRequest<Activity> = Activity.fetchRequest()
fetchRequest.entity = entity
//let sortDescriptor = NSSortDescriptor(key: #keyPath(Activity.timestamp), ascending: true)
//fetchRequest.sortDescriptors = [sortDescriptor]
do {
activitiesHistory = try CoreDataStack.context.fetch(fetchRequest)
//print(activitiesHistory)
} catch let error{
//handle error
print(error)
}
}
override func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return activitiesHistory.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let workout = activitiesHistory[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "historyCell", for: indexPath)
print(workout.value(forKey: "timestamp"))
cell.textLabel?.text = workout.value(forKey: "timestamp")as? String
//cell.textLabel?.text = "test"
return cell
}
}
This is worked for me.
var activities: [Activity] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addData()
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
do {
activities = try context.fetch(Activity.fetchRequest())
}
catch {
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.activities.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = self.activities[indexPath.row].timestamp
return cell
}
Result
Thanks for all your help! I found the solution:
The problem was that the data returned from the DB as of type "Date". The cell would simply show blank space and Xcode would show a warning or error. When I used DateFormatter() to convert the type to a formatted string, the cells displayed the data. Code below:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let workout = activities[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "historyCell", for: indexPath)
let time = workout.value(forKey: "timestamp")
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM"
let formatteddate = formatter.string(from: time as! Date)
cell.textLabel?.text = formatteddate
return cell
}
I'm trying to populate a table view with a large data. However, my tableview can only display 20 string objects. How do I simply display the rest of the data and update the table view each time the user scrolls to the end?
var people = [People]()
let configureSession = URLSessionConfiguration.default
let session = URLSession(configuration: configure)
//Setup the Api Key...
let apiKey = "https://congress.api.sunlightfoundation.com/legislators?apikey=(//Api Key here...)"
if error != nil{
print("ERROR: \(error?.localizedDescription)")
return
} else if let jsonData = data {
do{
let parsedJSON = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String: AnyObject]
guard let results = parsedJSON["results"] as? [[String: AnyObject]] else {return}
for result in results{
let name = myClass()
name.firstName = result["first_name"] as! String
self.people.append(name)
}
DispatchQueue.main.async {
//Reload the data
self.table.reloadData()
}
} catch let error as NSError{
print(error)
}
}
}).resume()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell.textLabel?.text = people[indexPath.row] //Only displays 20... Need to display more!
return cell!
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//Code to display the rest of the data goes here?
}
Make sure you return the correct value in numberOfRowsInSection method:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myLargeData.count
}
With provided myLargeData array there should be 30 rows in your tableView
You can use number of rows in section delegate of table view delegate to handle the more data in array.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return yourarray.count
}
I'm new to iOS. Doing project by watching tutorial which is written using Swift 2. It works when author runs app but not in my case.
ViewController:
var books = [[String: AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
searchBar.delegate = self
}
And the extension
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath)
// error on this line
if let volumeInfo = self.books[indexPath.row]["volumeInfo"] as? [String: AnyObject] {
cell.textLabel?.text = volumeInfo["title"] as? String
cell.detailTextLabel?.text = volumeInfo["subtitle"] as? String
}
return cell
}
}
The console output:
Please, help me to identify what is the cause.
You have to return books.count from numberOfRowsInSection, never "hard-code" that value if it's related to the data source array.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return books.count
}
PS: In Swift 3 you should use [String:Any] rather than [String:AnyObject]
I'm assuming a lot about your project but if you only have one section in your tableView, which is the default, you shouldn't use indexPath.section for your books dictionary. You should use indexPath.row as seen below
Change -
if let volumeInfo = self.books[indexPath.section]["volumeInfo"] as? [String: AnyObject]
To -
if let volumeInfo = self.books[indexPath.row]["volumeInfo"] as? [String: AnyObject] {