tableview cell action issue xcode - ios

So I am creating this todo app. It is on a tableview. And each cell when tapped or clicked should take you to a ask.com search to search for the item if it is not clear what the Item is. I have gotten it to search on ask.com with the code I have written. But the issue that I have coming up is that after the first click. The page doesn't refresh or update. I can click on the second or third cell and it wont search for what is in that particular cell. It keeps showing what is in the first cell. and won't change. I have tried clearing cells and it still keeps going through as the old search from the first time. Ex: Cell 1 : cleaning products Cell 2: a bike Cell 3: dog. No matter what cell I pick it will only show cleaning product. Even if I change cell 1 to another item. How can I fix this. Source code would be amazing.
import UIKit
class NewTableViewController: UITableViewController, NewCellDelegate, {
var news:[News]!
override func viewDidLoad() {
super.viewDidLoad()
loadData()
func loadData() {
news = [News]()
news = DataManager.loadAll(News.self).sorted(by: {$0.createdAt < $1.createdAt})
self.tableView.reloadData()
}
#IBAction func Save(_ sender: Any) {
let addAlert = UIAlertController(title: "ADD", message: "TODO", preferredStyle: .alert)
addAlert.addTextField { (textfield:UITextField) in
textfield.placeholder = "TODO"
}
addAlert.addAction(UIAlertAction(title: "Save", style: .default, handler: { (action:UIAlertAction) in
guard let title = addAlert.textFields?.first?.text else {return}
let newsave = News(title: title, completed: false, createdAt: Date(), itemIdentifier: UUID())
newsave.saveItem()
self.news.append(newsave)
let indexPath = IndexPath(row: self.tableView.numberOfRows(inSection: 0), section: 0)
self.tableView.insertRows(at: [indexPath], with: .automatic)
}))
addAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(addAlert, animated: true, completion: nil)
}
};
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return news.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! NewTableViewCell
cell.delegte = self
let news = self.news[indexPath.row]
cell.label.text = news.title
return cell
}
func tableView(tableView: UITableView, didSelectRowAt indexPath:
NSIndexPath) {
//getting the index path of selected row
let indexPath = tableView.indexPathForSelectedRow
//getting the current cell from the index path
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
//getting the text of that cell
let TODO = currentCell.textLabel!.text
let appURL = NSURL(string: "https://www.ask.com/web?q=\
(TODO))&o=0&qo=homepageSearchBox)")
if UIApplication.shared.canOpenURL(appURL! as URL) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(appURL! as URL, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(appURL! as URL)
}
}
}
}

I think it relates to search content change this
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
to
let currentCell = tableView.cellForRow(at: indexPath!) as! NewTableViewCell
&&& change this
let TODO = currentCell.textLabel!.text
to
let TODO = currentCell.label.text

Related

Swift - can't reload Data from TableView after add button action

I'm new to Swift and need your help.
I created a TableViewController with a custom cell.
Also I created a "add" Button in navigation bar to add a new value to my tableview.
Saving the values in Core Data and fetch them in viewWillAppear.
When pressing the add button a UIAlertController shows up which i had customized like i needed. I added a cancel action and a ok action but when i press the ok button from the alert the new value don't shows up in my tableview. I have to switch to an other viewcontroller that the tableview shows it.
I added groupsTableView.reloadData()on different points in my code but cant get it to work.
Hope someone can help me out!
Code from MasterViewController:
import UIKit
import CoreData
class MasterViewController: UITableViewController {
var groups: [Groups] = []
#IBOutlet weak var groupsTableView: UITableView!
var groupsTextField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
groupsTableView.delegate = self
groupsTableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
// Core date initialization
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Groups> = Groups.fetchRequest()
do {
groups = try managedContext.fetch(fetchRequest)
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not fetch groups")
}
navigationItem.leftBarButtonItem = editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject))
navigationItem.rightBarButtonItem = addButton
}
// MARK: - add new Group
#objc func insertNewObject() {
let addButtonAlert = UIAlertController(title: "Neue Gruppe", message: "Füge eine neue Gruppe deiner Liste hinzu", preferredStyle: .alert)
addButtonAlert.addTextField { (UITextField) in
self.groupsTextField = UITextField
self.groupsTextField?.placeholder = "Name der Gruppe"
self.groupsTextField?.clearButtonMode = .whileEditing
}
let okAction = UIAlertAction(title: "Hinzufügen", style: .default, handler: addNewGroup)
let cancelAction = UIAlertAction(title: "Abbrechen", style: .cancel, handler: nil)
addButtonAlert.addAction(okAction)
addButtonAlert.addAction(cancelAction)
self.present(addButtonAlert, animated: true, completion: nil)
}
func addNewGroup(_:UIAlertAction) -> Void {
let group = Groups(groupId: UUID(), groupTitle: groupsTextField!.text ?? "")
do {
try group?.managedObjectContext?.save()
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not save group")
}
}
// MARK: - Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let destination = segue.destination as? DetailViewController,
let selectedRow = self.groupsTableView.indexPathForSelectedRow?.row else {
return
}
destination.group = groups[selectedRow]
destination.title = groups[selectedRow].groupTitle
}
// MARK: - delete Group
func deleteGroup(at indexPath: IndexPath) {
let group = groups[indexPath.row]
guard let managedContext = group.managedObjectContext else {
return
}
managedContext.delete(group)
do {
try managedContext.save()
groups.remove(at: indexPath.row)
groupsTableView.deleteRows(at: [indexPath], with: .automatic)
} catch {
//TODO: error handling
print("Could not delete Group")
groupsTableView.reloadRows(at: [indexPath], with: .automatic)
}
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return groups.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = groupsTableView.dequeueReusableCell(withIdentifier: "GroupsTableViewCell", for: indexPath) as! GroupsTableViewCell
let object = groups[indexPath.row]
cell.groupTitleLabel?.text = object.groupTitle
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
deleteGroup(at: indexPath)
}
}
}
Add group item to your groups array and after that reload your tableview as shown below:-
func addNewGroup(_:UIAlertAction) -> Void {
let group = Groups(groupId: UUID(), groupTitle: groupsTextField!.text ?? "")
do {
try group?.managedObjectContext?.save()
self.groups.append(group)
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not save group")
}
}

Remove specific array element by cell text string value [swift 4]

I have two arrays for my UITableView. One holds the array items and the other holds the value of the array items in case they have a checkmark on them. I am having a problem now because my two arrays don't have the same IndexPath. I need something to delete the item in my selectedChecklist array by its string value. How can I do that?
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
checklist.remove(at: indexPath.row)
selectedChecklist.removeAll { $0 == String(cell.textLabel) }
myTableView.reloadData()
}
}
printed selectedChecklist
["Test", "Test2", "Test3", "Asdf", "Test2", "Test2", "Test"]
Here is my code for the whole array. I am struggling implementing the answers:
import UIKit
class ChecklistViewController: BaseViewController, UITableViewDelegate, UITableViewDataSource{
var dataHolder = [ListItem]()
var newChecklistItemString: String?
var alertInputTextField: UITextField?
#IBOutlet weak var myTableView: UITableView!
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var checkedItems: [ListItem] {
return dataHolder.filter { return $0.isChecked }
}
var uncheckedItems: [ListItem] {
return dataHolder.filter { return !$0.isChecked }
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dataHolder.count)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 18.0)
cell.textLabel?.text = dataHolder[indexPath.row].title
return cell
}
// checkmarks when tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (tableView.cellForRow(at: indexPath)?.accessoryType != .checkmark) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}else {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
tableView.deselectRow(at: indexPath, animated: true)
saveDefaults()
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
checkedItems[indexPath.row].isChecked = false
myTableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
myTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
addSlideMenuButton()
loadDefaults()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addNewObject(_ sender: Any) {
let alert = UIAlertController(title: "New Item", message: nil, preferredStyle: .alert)
alert.addTextField { (alertInputTextField) in
alertInputTextField.autocapitalizationType = .sentences
}
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Add", style: .default, handler: { (action) in
let textf = alert.textFields![0] as UITextField
let indexPath = IndexPath(row: self.dataHolder.count, section: 0)
self.dataHolder.append(ListItem(title: textf.text!, isChecked: false))
self.saveDefaults()
self.myTableView.insertRows(at: [indexPath], with: .automatic)
}))
self.present(alert, animated: true, completion: nil)
}
func loadDefaults()
{
self.dataHolder = UserDefaults.standard.array(forKey: "dataHolder") as? [ListItem] ?? []
}
func saveDefaults()
{
UserDefaults.standard.set(self.dataHolder, forKey: "dataHolder")
}
}
class ListItem {
var title: String
var isChecked: Bool
init(title: String, isChecked: Bool) {
self.title = title
self.isChecked = isChecked
}
}
You code is too complicated. As you are using a class as data source the extra arrays are redundant.
Remove checkedItems and uncheckedItems
var checkedItems: [ListItem] {
return dataHolder.filter { return $0.isChecked }
}
var uncheckedItems: [ListItem] {
return dataHolder.filter { return !$0.isChecked }
}
In cellForRow set the checkmark according to isChecked and reuse cells!
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 18.0) // better set this in Interface Builder
let data = dataHolder[indexPath.row]
cell.textLabel?.text = data.title
cell.accessoryType = data.isChecked ? .checkmark : .none
return cell
}
in didSelectRowAt toggle isChecked in the model and update only the particular row
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dataHolder[indexPath.row].isChecked.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
tableView.deselectRow(at: indexPath, animated: true)
saveDefaults()
}
In tableView:commit:forRowAt: delete the row at the given indexPath
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
dataHolder.remove(at: indexPath.row)
myTableView.deleteRows(at: [indexPath], with: .fade)
saveDefaults()
}
}
And you cannot save an array of a custom class to UserDefaults. I recommend to use a struct and Codable
struct ListItem : Codable {
var title: String
var isChecked: Bool
}
func loadDefaults()
{
guard let data = UserDefaults.standard.data(forKey: "dataHolder") else {
self.dataHolder = []
return
}
do {
self.dataHolder = try JSONDecoder().decode([ListItem].self, for: data)
} catch {
print(error)
self.dataHolder = []
}
}
func saveDefaults()
{
do {
let data = try JSONEncoder().encode(self.dataHolder)
UserDefaults.standard.set(data, forKey: "dataHolder")
} catch {
print(error)
}
}
Avoid using 2 array to "persist" your models. Instead you can generate a single Array with tuples :
var myArray: [(String, Bool)] = [("Test", false), ("Test1", false), ("Test2", false)]
Starting here the problem is simplified, and you will not have index path issue again
Edit
I've changed my code to support [ListItem] saving to UserDefaults- that comment brought by Leo Dabus I also changed a couple of lines that were inspired by vadian's code who appear to have a great coding style.
class ChecklistViewController: BaseViewController, UITableViewDelegate, UITableViewDataSource{
var dataHolder: [ListItem] = DefaultsHelper.savedItems
#IBOutlet weak var myTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataHolder.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 18.0)
let currentListItem = dataHolder[indexPath.row]
cell.textLabel?.text = currentListItem.title
cell.accessoryType = currentListItem.isChecked ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dataHolder[indexPath.row].isChecked.toggle()
DefaultsHelper.saveItems(items: dataHolder)
tableView.reloadRows(at: [indexPath], with: .none)
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
dataHolder.remove(at: indexPath.row)
DefaultsHelper.saveItems(items: dataHolder)
myTableView.reloadData()
myTableView.deleteRows(at: [indexPath], with: .automatic)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
myTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// be sure you've set your tableView's dataSource and delegate to this class (It's fine if you've handled this on the storyboard side)
addSlideMenuButton()
}
#IBAction func addNewObject(_ sender: Any) {
let alert = UIAlertController(title: "New Item", message: nil, preferredStyle: .alert)
alert.addTextField { (alertInputTextField) in
alertInputTextField.autocapitalizationType = .sentences
}
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Add", style: .default, handler: { (action) in
let textf = alert.textFields![0] as UITextField
let indexPath = IndexPath(row: self.dataHolder.count, section: 0)
let itemToInsert = ListItem(title: textf.text!, isChecked: false)
// self.dataHolder.append(itemToInsert)
// thought you would want this, it will add your notes in reverse chronological order
self.dataHolder.insert(itemToInsert, at: 0)
DefaultsHelper.saveItems(items: self.dataHolder)
self.myTableView.insertRows(at: [indexPath], with: .automatic)
}))
self.present(alert, animated: true, completion: nil)
}
}
Model classes:
// implementing NSObject and NSCoding to let us save this item in UserDefaults
class ListItem: NSObject, NSCoding{
var title: String
var isChecked: Bool
init(title: String, isChecked: Bool) {
self.title = title
self.isChecked = isChecked
}
// This code lets us save our custom object in UserDefaults
required convenience init(coder aDecoder: NSCoder) {
let title = aDecoder.decodeObject(forKey: "title") as? String ?? ""
let isChecked = aDecoder.decodeBool(forKey: "isChecked")
self.init(title: title, isChecked: isChecked)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(title, forKey: "title")
aCoder.encode(isChecked, forKey: "isChecked")
}
}
class DefaultsHelper{
private static let userDefaults = UserDefaults.standard
private static let dataKey = "dataHolder"
static var savedItems: [ListItem] {
guard let savedData = userDefaults.data(forKey: dataKey) else { return [] }
do{
let decodedData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(savedData)
return decodedData as? [ListItem] ?? []
}catch{
print("could not fetch items- you may handle this", error)
}
return []
}
static func saveItems(items: [ListItem]){
do{
let encodedData = try NSKeyedArchiver.archivedData(withRootObject: items, requiringSecureCoding: false)
userDefaults.set(encodedData, forKey: dataKey)
}catch{
print("could not save items- you may handle this", error)
}
}
}

How do You Inherit a Custom TableViewController For An TableView in a ViewController

So I have a custom SwipeCellTableView class that I inherited from when using UITableViewControllers. Now I want to just use that class for an ib outlet table view controller in a regular View Controller. It is proving to be very difficult and seemingly not worth it anymore. Can this be done?
Here is the superclass which inherits from a TableViewController, I have tried to change it to inherit from a view controller but it just doesn't work out
class SwipeTableViewController: UITableViewController, SwipeTableViewCellDelegate {
var cell: UITableViewCell?
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 80.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SwipeTableViewCell
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
self.updateModel(at: indexPath)
}
deleteAction.image = UIImage(named: "delete-icon")
return [deleteAction]
}
func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
var options = SwipeTableOptions()
options.expansionStyle = .destructive
//options.transitionStyle = .reveal
return options
}
func updateModel(at indexPath: IndexPath){
//update data model
print("Item deleted from super class")
}
Here is the View Controller I'm trying to access it from:
class GoalsViewController: UIViewController, SwipeTableViewController {
#IBOutlet weak var categoryTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addCategoryPressed(_ sender: UIButton) {
performSegue(withIdentifier: "showgoalsSeg", sender: self)
}
For reference on how I was using it before when using an actual TableViewController:
class CategoryViewController: SwipeTableViewController {
var categories: Results<Category>? //optional so we can be safe
override func viewDidLoad() {
super.viewDidLoad()
loadCategory()
tableView.rowHeight = 80.0
tableView.separatorStyle = .none
}
//MARK: - Tableview Datasource Methods
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//Only get the count of categories if it's nil, else 1
return categories?.count ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//fetching cell from super view
let cell = super.tableView(tableView, cellForRowAt: indexPath)
cell.textLabel?.text = categories?[indexPath.row].name ?? "No Categories Added Yet"
cell.backgroundColor = UIColor(hexString: categories?[indexPath.row].color ?? "000000")
return cell
}
//MARK: - Tableview Delegate Methods
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToItems", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! ToDoListViewController
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categories?[indexPath.row]
}
}
//MARK: - Add New Categories
#IBAction func addButtonPressed(_ sender: Any) {
var textField = UITextField()
let alert = UIAlertController(title: "Add New Category", message: "", preferredStyle: .alert)
let action = UIAlertAction(title: "Add Category", style: .default) { (action) in
let newCategory = Category()
newCategory.name = textField.text!
newCategory.color = UIColor.randomFlat.hexValue()
self.save(category: newCategory)
}
alert.addAction(action)
alert.addTextField { (field) in
textField = field
textField.placeholder = "Add a new category"
}
present(alert, animated: true, completion: nil)
}
func save(category: Category){
let realm = try! Realm()
do {
try realm.write{
realm.add(category)
}
} catch {
print("error saving context")
}
tableView.reloadData()
}
override func updateModel(at indexPath: IndexPath) {
super.updateModel(at: indexPath)
let realm = try! Realm()
if let categoryForDeletion = self.categories?[indexPath.row]{
do{
try realm.write{
realm.delete(categoryForDeletion)
}
} catch {
print("error deleting cell")
}
//tableView.reloadData()
}
}
func loadCategory(){
let realm = try! Realm()
categories = realm.objects(Category.self)
tableView.reloadData()
}
Is this even worth persuing? Or doable?

How can I get the index path.row of first table view to use it in the second table view using Swift3 , Xcode8

I have two table views in my project , Can any one help me to get the index path.row of first table view which is the main table to use in the second table view which is the sub table of the main table.
this is My mainTableView.
import UIKit
class MainTableViewController: UITableViewController {
var womenArray = [women]()
var data : [String] = []
let backendless = Backendless()
override func viewDidLoad() {
super.viewDidLoad()
data = ["1","2","3","4","5"]
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = data[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.womenArray.removeAll()
if (indexPath.row == 0) {
let whereClause = "Desc = 'test'"
let dataQuery = BackendlessDataQuery()
dataQuery.queryOptions.pageSize=50
dataQuery.whereClause = whereClause
backendless.data.of(women.ofClass()).find(dataQuery,response: {(result: BackendlessCollection?) -> Void in
let data = result?.getCurrentPage()
for obj in data! as! [women] {
self.womenArray.append(obj)
}
let SubWomenView: WomenSubTableViewController = self.storyboard!.instantiateViewController(withIdentifier: "subwomen") as! WomenSubTableViewController
SubWomenView.subWomenArray = self.womenArray
self.navigationController?.pushViewController(SubWomenView, animated: true)
},
error: { (fault: Fault?) -> Void in
print(fault)
let alert = UIAlertController(title: "info", message:"يرجى الاتصال بالانترنيت", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
})
self.present(alert, animated: true){}
})
}else if indexPath.row == 1{
let whereClause = "Desc = 'test2'"
let dataQuery = BackendlessDataQuery()
dataQuery.queryOptions.pageSize=50
dataQuery.whereClause = whereClause
backendless.data.of(women.ofClass()).find(dataQuery,response: {(result: BackendlessCollection?) -> Void in
let data = result?.getCurrentPage()
for obj in data! as! [women] {
self.womenArray.append(obj)
}
let SubWomenView: WomenSubTableViewController = self.storyboard!.instantiateViewController(withIdentifier: "subwomen") as! WomenSubTableViewController
SubWomenView.subWomenArray = self.womenArray
self.navigationController?.pushViewController(SubWomenView, animated: true)
},
error: { (fault: Fault?) -> Void in
let alert = UIAlertController(title: "info", message:"يرجى الاتصال بالانترنيت", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
})
self.present(alert, animated: true){}
})
}
}
}
and this is My SubTableView.
import UIKit
class SubTableViewController: UITableViewController {
var subWomenArray = [women]()
let backendless = Backendless()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return subWomenArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? WomenSubCell{
let ImgURL = URL(string : self.subWomenArray[(indexPath as NSIndexPath).row].ImgURL!)
cell.WomenImgView.sd_setImage(with: ImgURL)
return cell
}else{
let cell = WomenSubCell()
let ImgURL = URL(string : self.subWomenArray [(indexPath as NSIndexPath).row].ImgURL)
cell.WomenImgView.sd_setImage(with: ImgURL)
return cell
}
}
}
You can create a property on your Sub Table View and assign the value of indexPath.row to it as you are assigning the array in the below line:
SubWomenView.subWomenArray = self.womenArray
maybe use tuple is easier to understand.
SubWomenView.subWomenArray =(index.row , self.womenArray)
In subtableview,
var subWomenArray : (Int,[women])
Then subWomenArray.1 refer to your [women]

Firebase Data not showing in TableView

So basically I want to get the data from Firebase and put it in the tableView and then when a cell is deleted I want to remove the data from firebase and the table view...but with my code the data is NOT even showing up in the TableView and i really don't know what's wrong...?
Here's my Database structure if it helps:
Structure
I put the data in Courses then a childByAutoId which contains CourseName,AmountOfHoles and AddedDate then get it back in a snapshot, store the snapshot in an array called courses and then get the variables for the cell in cellForRowAtIndexPath but somehow the cell is not showing on the tableView...then I would delete the cell and data in commitEditingStyle but it doesn't even get to that because the cells don't show up...
I'm new to StackOverflow, so please excuse me if something seems stupid or wrong ...dont bother to tell me tho..
class CoursesViewController: UITableViewController {
var ref = FIRDatabaseReference.init()
override func viewDidLoad() {
ref = FIRDatabase.database().reference()
tableView.allowsMultipleSelectionDuringEditing = false
//let a = ref.childByAutoId()
//a.setValue("hi")
}
var courses: [FIRDataSnapshot]! = []
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let CoursesRef = ref.child("Courses")
CoursesRef.observeEventType(.ChildAdded, withBlock: { snapshpt in
self.courses.append(snapshpt)
})
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.courses.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
let cell: UITableViewCell! = self.tableView .dequeueReusableCellWithIdentifier("ItemCell", forIndexPath: indexPath)
let courseSnap: FIRDataSnapshot! = self.courses[indexPath.row]
let course = courseSnap.value
let coursename = course?.objectForKey("CourseName") as! String
let amountofholes = course?.objectForKey("AmountOfHoles") as! String
let addeddate = course?.objectForKey("AddedDate") as! String
cell.textLabel?.text = coursename + " " + amountofholes + " Holes"
cell.detailTextLabel?.text = addeddate
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Find the snapshot and remove the value
let courseitem = courses[indexPath.row]
courseitem.ref.removeValue()
}
}
#IBAction func addButtonDidTouch(sender: AnyObject) {
// Alert View for input
let alert = UIAlertController(title: "Course Item",message: "Add Course",preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save", style: .Default) { (action: UIAlertAction) -> Void in
//Get Date String
let date = NSDate()
print(date)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy 'at' HH:mm"
let dateString = dateFormatter.stringFromDate(date)
print(dateString)
//
let courseField = alert.textFields![0]
let holesField = alert.textFields![1]
let Courses = self.ref.child("Courses").childByAutoId()
let course = ["AddedDate": dateString as AnyObject,
"CourseName": courseField.text as! AnyObject,
"AmountOfHoles": holesField.text as! AnyObject]
Courses.setValue(course)
}
//Cancel
let cancelAction = UIAlertAction(title: "Cancel", style: .Default) { (action: UIAlertAction) -> Void in
}
//TextField placeholder in alert
alert.addTextFieldWithConfigurationHandler {
(courseField: UITextField!) -> Void in
courseField.placeholder = "Course Name"
}
alert.addTextFieldWithConfigurationHandler {
(holesField: UITextField!) -> Void in
holesField.placeholder = "Holes (6/9/18)"
}
//Add alert
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert, animated: true, completion: nil)
}
}
Man you have to insert your code when a snapshot is found out !
I think you can go like this :
CoursesRef.observeEventType(.ChildAdded, withBlock: { snapshot in
self.courses.append(snapshot)
self.yourTable.insertRowsAtIndexPaths([NSIndexPath(forRow: self.courses.count-1, inSection: 0)], withRowAnimation: .Bottom)
})
check with this code
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(self.courses.count > 0){
tablecount = self.courses.count
} else {
tablecount = 0
self.table.reloaddata()
}
return tablecount
}

Resources