The data that I am retrieving from Firebase is not showing up in my table view, but it is showing up in my snapshot. What am I missing?
Here is my code:
import UIKit
import Firebase
import FirebaseDatabase
class NewConversationViewController: UITableViewController {
var users = [User]()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
tableView.delegate = self
tableView.dataSource = self
fetchUser()
tableView.isHidden = false
}
func fetchUser() {
Database.database().reference().child("users").observeSingleEvent(of: .value, with: { snapshot in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
user.setValuesForKeys(dictionary)
self.users.append(user)
}
print(snapshot)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}, withCancel: nil)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let user = users[indexPath.section]
cell.textLabel?.text = user.name
return cell
}
}
Related
I have a tableview where I have added the ability to move the location of rows. I am able to use the "swapAt" function to update my array and it works fine. The problem is that when I close and re-open the app, the rows continue to show in their old IndexPath. How can I also update the index location in the PersistentContainer so that when I open the app, it is updated with the new IndexPath?
I tried calling the save method of the context but it does not work.
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var toDoList = [Item] ()
var count: Int {
toDoList.count
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addItem))
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editItem))
title = "Todo"
loadItem()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return toDoList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath)
cell.textLabel?.text = toDoList [indexPath.row].title
if toDoList[indexPath.row].checkmark == true {
cell.accessoryType = .checkmark }
else {
cell.accessoryType = .none
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if toDoList[indexPath.row].checkmark == false {
toDoList[indexPath.row].checkmark = true } else {
toDoList[indexPath.row].checkmark = false
}
tableView.reloadData()
saveItem()
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
toDoList.swapAt(sourceIndexPath.row, destinationIndexPath.row)
saveItem()
}
#objc func addItem () {
let ac = UIAlertController(title: "Add new category", message: nil, preferredStyle: .alert)
var textField = UITextField()
let submitAction = UIAlertAction(title: "Add", style: .default) { (action) in
let newItem = Item(context: self.context)
newItem.title = textField.text
newItem.checkmark = false
newItem.order = Int64(self.count)
self.toDoList.append(newItem)
self.saveItem()
}
ac.addTextField { (alertTextField) in
alertTextField.placeholder = "Create new item"
textField = alertTextField
}
ac.addAction(submitAction)
present(ac, animated: true, completion: nil)
}
func saveItem () {
do {
try context.save()
} catch {
print("This is the \(error)")
}
self.tableView.reloadData()
}
func loadItem () {
let request: NSFetchRequest<Item> = Item.fetchRequest()
let sortRequest = NSSortDescriptor(key: "order", ascending: true)
request.sortDescriptors = [sortRequest]
do {
toDoList = try context.fetch(request)
} catch {
print("the error is \(error)")
}
tableView.reloadData()
}
#objc func editItem () {
if tableView.isEditing {
tableView.isEditing = false
} else {
tableView.isEditing = true
}}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
context.delete(toDoList[indexPath.row])
saveItem()
self.toDoList.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
I would tackle this problem by having an index property in the Coredata entity; this index reflects the position of the element in the table view. In the swapAtFunction add the logic to switch the index properties of the two elements.
Then, when you fetch the entities, you add a predicate to your request, to sort the elements by the index property.
let fetchRequest = NSFetchRequest<EntityName>(entityName: "EntityName")
let sortDescripor = NSSortDescriptor(key: "index", ascending: true)
fetchRequest.sortDescriptors = [sortDescripor]
Then execute fetchRequest as you normally would, and assign the resulting array to the UICollectionView's Datasource.
I have searched Stack Overflow well and truly with a variety of different options offered but none I can seem to get working.
I have an app which has a glossary of terms for NFL (e.g. offence/defence) etc. It comes from a JSON API and is stored locally. I would like to sort the data programmatically, so the terms are all listed in their respective sections ("A", "B", "C" etc.) alphabetically.
View Controller:
import UIKit
class GlossaryVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let glossaryCellId = "GlossaryCell"
var glossarys = [Offence]()
var filteredGlossarys = [Offence]()
private var subCategorySet: Set<String> = []
private var glossarysDictionary: [String: [Offence]] = [:]
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var noResultsView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
filteredGlossarys = glossarys
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = UIColor.clear
searchBar.delegate = self
noResultsView.isHidden = true
hideKeyboardWhenTappedAround()
}
override func viewDidAppear(_ animated: Bool) {
DataProvider.getData(with: .GLOSSARY_DATA_URL) { (letters) in
self.glossarys = letters.flatMap { $0.offences }
self.filteredGlossarys = self.glossarys
self.groupGlossarys()
}
}
func groupGlossarys() {
glossarysDictionary.removeAll()
subCategorySet.removeAll()
for glossary in filteredGlossarys {
subCategorySet.insert(glossary.glossaryLetter!)
}
for subCategory in subCategorySet {
glossarysDictionary[subCategory] = []
}
for glossary in filteredGlossarys {
var list = glossarysDictionary[glossary.glossaryLetter!]
list?.append(glossary)
glossarysDictionary[glossary.glossaryLetter!] = list
}
checkAndShowTableView()
}
func checkAndShowTableView() {
if subCategorySet.count > 0 {
tableView.isHidden = false
noResultsView.isHidden = true
tableView.reloadData()
} else {
tableView.isHidden = true
noResultsView.isHidden = false
}
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
func numberOfSections(in tableView: UITableView) -> Int {
return subCategorySet.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let subCategoryList = Array(subCategorySet)
return subCategoryList[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let subCategoryList = Array(subCategorySet)
let glossaryList = glossarysDictionary[subCategoryList[section]]
return glossaryList!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let glossaryCell = tableView.dequeueReusableCell(withIdentifier: glossaryCellId, for: indexPath) as? GlossaryCell else {
fatalError("Unable to dequeue contact cell")
}
let subCategoryList = Array(subCategorySet)
let glossaryList = glossarysDictionary[subCategoryList[indexPath.section]]
glossaryCell.configure(glossary:(glossaryList?[indexPath.row])!)
return glossaryCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.clear
cell.contentView.backgroundColor = UIColor.clear
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let viewGlossaryDetailsVC = segue.destination as? GlossaryDetailsVC,
let section = tableView.indexPathForSelectedRow?.section, let row = tableView.indexPathForSelectedRow?.row {
let subCategoryList = Array(subCategorySet)
let glossaryList = glossarysDictionary[subCategoryList[section]]
let glossarys = glossaryList?[row]
viewGlossaryDetailsVC.glossarys = glossarys
}
}
}
extension GlossaryVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if !searchText.isEmpty {
filteredGlossarys = glossarys.filter({ (glossary) -> Bool in
let glossaryTitleRange = glossary.glossaryTitle?.range(of: searchText, options: .caseInsensitive)
let glossaryDescriptionRange = glossary.glossaryDescription?.range(of: searchText, options: .caseInsensitive)
let glossaryKeywordsRange = glossary.glossaryKeywords?.range(of: searchText, options: .caseInsensitive)
return glossaryTitleRange != nil || glossaryDescriptionRange != nil || glossaryKeywordsRange != nil
})
} else {
filteredGlossarys = glossarys
}
groupGlossarys()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
}
I have so far tried the sorted(by: {}) method on the let subCategoryList = Array(subCategorySet) in the titleForHeaderInSection which does arrange the section headers alphabetically but the data doesn't change. So you end up having words beginning with "H" in the "A" subcategory.
Data is grouped based on a "letter" key in the database, e.g., so all "A" are grouped together, etc.
Any help would be appreciated, all I want to do is sort it alphabetically and I feel a little out of my depth.
I want to show the image in the Firebase database in my CollectionView.
I have tried but without result. Please if you want more information ask me.
THIS IS MY IMAGE REFERENCE
which I download the single image from firebase.
import Foundation
import UIKit
import FirebaseStorage
struct Utility {
let storageRef = Storage.storage().reference(forURL: "gs://****-******.appspot.com/")
func getImage(withName name: String, completion: #escaping (UIImage?) -> ()) {
let imageRef = storageRef.child("images").child(name)
imageRef.getData(maxSize: 2 * 1024 * 1024) { (data, error) in
if error == nil && data != nil {
let image = UIImage(data: data!)
completion(image)
} else {
completion(nil)
}
}
}
}
THIS IS MY FIREBASE DICTIONARY
which I retrieve the information from the database.
import Foundation
class Place {
let kImageName = "imageName"
var imageName: String!
init(withDictionary dict: [String : Any]) {
self.imageName = dict[kImageName] as? String
}
}
THIS IS MY VIEW CONTROLLER
which I want to show my array image in my CollectionView inside a TableViewCell.
import UIKit
import AVFoundation
import FirebaseDatabase
import FirebaseStorage
class GuidaTuristicaCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imagePlaces: UIImageView!
var place: Place! {
didSet {
if let place = place {
Utility().getImage(withName: place.imageName!, completion: { (image) in
DispatchQueue.main.async {
self.imagePlaces.image = image
}
})
}
}
}
}
class GuidaTuristicaTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
}
class GuidaTuristicaViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
var place: Place?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! GuidaTuristicaTableViewCell
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! GuidaTuristicaCollectionViewCell
cell.place = place
return cell
}
}
I've read a lot of related questions here, but am still struggling with populating my tableview. I get the result from the print(firstname) and print(lastname) in the console. But nothing appears in the tableview.
The Table view has a Prototype cell with identifier BasicCell.
Any idea why the table is not populating?
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var listTableView: UITableView!
let URL_GET_PERSONAGE = "http://somesite.net/somescript.php"
var firstnames: [String] = []
var lastnames: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: URL_GET_PERSONAGE)
do{
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["teams"] as? NSArray{
for index in 0..<arrJSON.count{
let aObject = arrJSON[index] as? [String : AnyObject]
firstnames.append(aObject?["fname"] as! String)
lastnames.append(aObject?["lname"] as! String)
}
print(firstnames)
print(lastnames)
listTableView.reloadData()
}
}
catch {
}
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return self.firstnames.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell! = self.listTableView.dequeueReusableCell(withIdentifier: "BasicCell", for: indexPath as IndexPath) as UITableViewCell!
cell.textLabel?.text = self.firstnames[indexPath.row]
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Is it possible to get the data from the external database when a UItableViewCell is pressed?
I managed to create a UItableView where I am displaying the data from the database. If I press a cell then all the data that are linked to it should be displayed. For eg. if I have 4 main categories in the database such as TOOLS, OTHERS, SECURITY, PETS and each of them has its sub-catecory and are linked with each other in the database. So if I click on Pets, it should filter out and only Show me CATS, DOGS, COWS, LIONS. When I run this SQL I am able to get the information but cant figure it this out on Swift.
UItableViewCell is in my FirstviewController and its the Main Category .
When I click here it goes to my destination VC and has the table again in here.enter image description here
DestViewController is the sub-category
enter image description here
My CategoryList_ViewController.swift
import Foundation
import UIKit
import WebKit
class CategoryList_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let url = NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\cat.php")
let data = NSData(contentsOfURL: url!)
values = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CategoryList_TableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "catView" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let value = values[indexPath.row]
let controller = segue.destinationViewController as! SubCatergory_ViewController
controller.cate_Id = value["id"] as! String
controller.catTitleRec = value["NAME"] as! String
}
}
}
}
my SubCatergory_ViewController.swift
import Foundation
import UIKit
import WebKit
class SubCatergory_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var caID: UILabel!
#IBOutlet weak var catTitle_Label: UILabel!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
var catTitleRec = ""
var cate_Id = ""
override func viewDidLoad() {
super.viewDidLoad()
catTitle_Label.text = catTitleRec
caID.text = cate_Id
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let request = NSMutableURLRequest(URL: NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\subcat.php")!)
request.HTTPMethod = "GET"
let postString = "a=\(cate_Id)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! subCateListTableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
}
and my subcat.php
<?php
$connection = mysql_connect(........);
$catefilter = $_GET['a'];
if(!$connection){
die('Connection Failed');
}
else{
$dbconnect = #mysql_select_db($database_UNIASSIGNMENT, $connection);
if(!$dbconnect){
die('Could not connect to Database');
}
else{
$query = 'SELECT category_group.group_id , category.NAME FROM category_group LEFT JOIN category ON category.id = category_group.category_id WHERE category_group.group_id =' . $catefilter ;
$resultset = mysql_query($query, $connection);
$records= array();
while($r = mysql_fetch_assoc($resultset)){
$records[] = $r;
}
echo json_encode($records);
}
}
?>
My first VC works fine but my second VC doesnot get the data
Thanks for your time :)
SK
To access the cell that has been pressed, you need to call the didSelectRowAtIndexPath function.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let value = values[indexPath.row]
let vc = storyboard?.instantiateViewController(withIdentifier: "SubCatergory_ViewController") as! SubCatergory_ViewController
vc.cate_Id = value["NAME"] as! String
//self.navigationController?.pushViewController(vc, animated: true)
self.present(vc, animated: true, completion: nil)
}
First you get the value out of your values Array on the indexPark.row. Then you instantiate your second viewController.
Then you set your String value of cate_Id to the desired String value of your item value. And then you just need to present the new viewController.
If you're using a UINavigationController and you want a "back" button, then you use: self.navigationController?.pushViewController(vc, animated: true)
If you just want to present the viewController, you use self.present(vc, animated: true, completion: nil)
Comment or uncomment whatever presentation method you prefer.