I am having trouble communicating with the "TableView". How can I solve the problem?
Error Image
Code Image
var arrayOfData = [cellData]()
var fullname1 : String!
var code1 : String!
var name1 : String!
var buy1 : Double!
var sell1 : Double!
var change_rate1 : Double!
var update_date1 : Double!
var arrayFullName : [String] = ["asdas","asds","asds","sadas","asdasd","asdas"]
#IBOutlet weak var tblDoviz: UITableView!
#IBOutlet weak var openBarButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
arrayOfData = [cellData(fullName: "Amerikan Doları", name: "", code: "USD", updateDate: 2, changeRate: 2, buy: 3.44, sell: 3.47)]
openBarButton.target = self.revealViewController()
openBarButton.action = Selector("revealToggle:")
tblDoviz.delegate = self
tblDoviz.dataSource = self
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
/* Doviz Sitesinden Bilgiler Çekiliyor */
let url = NSURL(string: "http://www.doviz.com/api/v1/currencies/all/latest")
let task = URLSession.shared.dataTask(with: url as! URL){(data,response,error) ->Void in
if error != nil
{
}
else
{
if let urlContent = data
{
do
{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if let currencyRate = jsonResult as? NSArray
{
for i in 0..<currencyRate.count
{
if let name = (currencyRate[i] as? NSDictionary)?["name"] as? String
{
self.name1 = name
}
if let fullname = (currencyRate[i] as? NSDictionary)?["full_name"] as? String
{
self.fullname1 = fullname
}
if let change_rate = (currencyRate[i] as? NSDictionary)?["change_rate"] as? Double
{
self.change_rate1 = change_rate
}
if let code = (currencyRate[i] as? NSDictionary)?["code"] as? String
{
self.code1 = code
}
if let update_date = (currencyRate[i] as? NSDictionary)?["update_date"] as? Double
{
self.update_date1 = update_date
}
if let buying = (currencyRate[i] as? NSDictionary)?["buying"] as? Double
{
self.buy1 = buying
}
if let selling = (currencyRate[i] as? NSDictionary)?["selling"] as? Double
{
self.sell1 = selling
}
//Array'a Yükleme Yapılıyor
//cellData.init(fullName: self.fullname1, name: self.name1, code: self.code1, updateDate: self.update_date1, changeRate: self.change_rate1, buy: self.buy1, sell: self.sell1)
//self.arrayOfData = [cellData(fullName: self.fullname1, name: self.name1, code : self.code1, updateDate: self.update_date1, changeRate: self.change_rate1, buy: self.buy1, sell: self.sell1)]
//print(self.arrayOfData)
//print(cellData())
}
print(self.arrayFullName.count)
}
}
catch
{
}
}
}
}
task.resume()
//--------------------------------------------------
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDoviz",for:indexPath) as! DovizCell1
Error-------------------------------------
cell.lblText.text = arrayFullName[indexPath.row]
Error -----------------------------------
return cell as DovizCell1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 94
}
}
Try adding this to your code
let cell:DovizCell? = tableView.dequeueReusableCell(withIdentifier: "cellDoviz",for:indexPath) as! DovizCell
if cell == nil {
cell = NSBundle.mainBundle().loadNibNamed("DovizCell").first as! DovizCell
}
Your DovizCell might have been nil which is why the code crashed
Related
When I open the view it opens up quickly and doesn't show any errors but when I reopen it, it gives me 'fatal error'. This is a tableview inside the ViewController which is getting me the data but when I reopen the view it gives error.
The tableview is embedded inside the view controller when I call the tableview again it gives fatal error index out of range inside the ViewController. This needs to be solved I think issue is in my number of rows in section returning the array.
import UIKit
import Alamofire
import Foundation
protocol Quantitypass {
func qtypass(qty: String, product_id: String)
}
public struct QtyCart {
var qty : String!
public init(qty: String) {
self.qty = qty
}
}
public struct FavouriteCart {
var p_name : String!
var p_price : String!
var p_id : String!
var qty: String!
public init(p_name: String , p_price: String , p_id : String, qty: String) {
self.p_name = p_name
self.p_price = p_price
self.p_id = p_id
self.qty = qty
}
}
public struct favSection {
var favitems: [FavouriteCart]
public init(favitems: [FavouriteCart] ) {
self.favitems = favitems
}
}
public struct MyVariables {
static var product2 = "p_id"
}
public var cartData: [favSection] = []
class newCartViewController: UIViewController {
#IBAction func btnSubmit(_ sender: UIButton) {
self.loadnextVC()
}
func loadnextVC() {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "finalVC")
self.present(newViewController, animated: true, completion: nil)
}
#IBOutlet weak var lblPreorder: UILabel!
#IBOutlet weak var lblOrdermethod: UILabel!
#IBOutlet weak var lblTotalAmount: UILabel!
// public var itemsData: [Item] = []
var lblOrder = String()
// let productPrice = UserDefaults.standard.object(forKey: "p_price")
let cartid = UserDefaults.standard.object(forKey: "deviceUUID") as? String
let getApi = RestaurantAPI.self
var qtyData: [QtyCart] = []
// var currentSection = 0
// var currentRow = 1
// var calculation1 = cartTableViewCell()
#IBOutlet weak var tableView: UITableView!
#IBAction func dismiss(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
self.lblTotalAmount.text = ""
}
//public var cartData: [FavouriteCart] = []
var refreshControl = UIRefreshControl()
var buttonClicked = statusViewController.self
var btn2 = UserDefaults.standard.object(forKey:"button1") as? Bool
var btn3: Bool = true
weak var delegate: DetailsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.getTotal1()
print("#------/\(cartData.count)")
//self.updateLabel(withString: lblTotalAmount.text)
if btn2 != btn3 {
lblPreorder.isHidden = true
lblOrdermethod.isHidden = false
print("BUTTONCLICKED")
UserDefaults.standard.removeObject(forKey: "button1")
} else if btn2 == btn3 {
lblPreorder.isHidden = false
lblOrdermethod.isHidden = true
print("BUTTON-NOT-CLICKED")
UserDefaults.standard.removeObject(forKey: "button1")
}
// if #available(iOS 10.0, *) {
// tableView.refreshControl = refreshControl
// } else {
// tableView.addSubview(refreshControl)
//
// }
// self.refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
// self.refreshControl.addTarget(self, action: #selector(newCartViewController.refreshData), for: UIControlEvents.valueChanged)
//
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.view.addSubview(self.tableView)
self.tableView.dataSource = self
self.tableView.delegate = self
self.getTotal1()
self.getFav()
self.tableView.reloadData()
// self.updateTableview()
// self.getTotal1()
}
func getFav() {
getFav(completionHandler: { success in
if success {
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
})
}
//TOTAL API CALL:
func getTotal1() {
if cartid != nil {
let request = getApi.getamountcartGetWithRequestBuilder(restId: "17", cartId: cartid!)
Alamofire.request(request.URLString, method: .get , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("123321#######/\(response)")
let res = response
print("101res/\(res)")
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
// var grandtotal: Any? = value["total"]
if let grandtotal = value["total"] as? Double {
self.lblTotalAmount.text = String(grandtotal)
print("!#/\(String(grandtotal))")
var g = String(grandtotal)
UserDefaults.standard.set(g, forKey: "g")
}
// self.tableView.reloadData()
}
}
}
}
}
}
//
// Mark: getting all cart items:-->
func getFav(completionHandler: #escaping (Bool) -> Void){
if cartid != nil {
let request = getApi.displaycartGetWithRequestBuilder(restId: "17", cartId:cartid!)
Alamofire.request(request.URLString, method: .get , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("123321/\(response)")
let res = response
print("101res/\(res)")
// let total = cartData
// print("cartd1/\(total)")
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
print("2222/\(response)")
if let response = value["cartdata"] as? [String: AnyObject] {
let cart = response["simple"] as! [[String: AnyObject]]
// let total = value["total"] as! [String: Any]
// print("1231231231234/\(total)")
//let userdata: [Favourites] = []
//
var cartitems: [FavouriteCart] = []
for (_ , value) in cart.enumerated() {
let obj = value
let p_name = obj["p_name"] as! String
let p_price = obj["p_price"] as! String
let p_id = obj["p_id"] as! String
let qty = obj["qty"] as! String
// UserDefaults.standard.set(qty, forKey: "qty")
let item = FavouriteCart(p_name: p_name, p_price: p_price, p_id: p_id, qty: qty)
cartitems.append(item)
DispatchQueue.main.async{
print("RELOADED-----ON-----API")
cartData.append(favSection(favitems: cartitems))
self.tableView.reloadData()
}
}
}
print("COMPLETION-------------HANDLER")
completionHandler(true)
}
}
else
{
let myAlert = UIAlertController(title:"Alert",message:value["error_msg"] as? String,preferredStyle:UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title:"OK",style:UIAlertActionStyle.default , handler: nil)
myAlert.addAction(okAction)
}
}
}
}
}
// Mark:--> Delete items from cart.
// func delFav(p_id: String ,completionHandler: #escaping (Bool) -> Void) {
func delFav(p_id: String, completionHandler: #escaping (Bool) -> Void){
//var product1 = UserDefaults.standard.object(forKey: "p_id")
//print("this is my \(product1)")
let request = getApi.deleteproductcartGetWithRequestBuilder(restId: "17", cartId: cartid!, productId: p_id , freeDish: "none", type: "simple")
Alamofire.request(request.URLString, method: .delete , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("del favvvvvvvvv\(response)")
print("<<DELETED ------------ ITEM>>")
//print(response)
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
let response = value["cartdata"] as? [String]
print("10001 - > /\(response)")
//self.tableView.reloadData()
} else
{
print("error message")
}
}
}
// completionHandler(true)
}
}
func delterow(p_id: String) {
self.delFav(p_id: p_id, completionHandler: {sucess in
if sucess {
self.tableView.reloadData()
print("DELETED_ITEM")
}
})
}
func updateTotal(withString string: String?) {
lblTotalAmount.text = string
}
}
extension newCartViewController: UITableViewDelegate , UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90;
}
// func numberOfSections(in tableView: UITableView) -> Int {
// return cartData.count
// }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return sectionsData[section].items.count
// return cartData[section].favitems.count
// return cartData[section]..count
return cartData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cartTablecell", for: indexPath) as! cartTableViewCell
let item: FavouriteCart = cartData[indexPath.section].favitems[indexPath.row]
cell.btnsub1.tag = indexPath.row
cell.btnadd1.tag = indexPath.row
cell.lblItemName.text = item.p_name
cell.productPrice.text = item.p_price
cell.lblprice.text = item.p_price
cell.lblQuantity.text = item.qty
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool{
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
if cartData.isEmpty{
print("EmptyCart")
}else {
print("0-0/\(cartData.count)")
// let item: Item = sectionsData[indexPath.section].items[indexPath.row]
let item: FavouriteCart = cartData[indexPath.section].favitems[indexPath.row]
self.tableView.beginUpdates()
cartData.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.delterow(p_id: item.p_id)
self.getTotal1()
self.tableView.endUpdates()
}
}
}
}
It was giving the error because the rows were saved at local but I was calling the data again changes are :
have to delete the whole cart when close the view
#IBAction func dismiss(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
self.lblTotalAmount.text = ""
cartData.removeAll()
}
I think self.tableView.dataSource = self & self.tableView.delegate = self should be in viewDidLoad method. Adding it to viewDidLoad might work.
view the video of problem here
Im trying to make my infinite scroll work smoothly, before i had it working in a way where when the user reachs a certain item count in the table, it would load the others but while doing the load a Footer Activity indicator would appear, then dissapear and add the next batch of rows... which i kinda found annoying later on.. so i wanned to opmitized it. i want the tableview to initially load 100 items, then when the user is just around row 10 it would start to load the next 100 items and rows... the thing is.. everytime it makes the call.. the uitableview kinda hangs...
I did eliminate some trivial code here like the segmented control and letter buttons.. etc,
//
// VCrestlist.swift
// AsyncUITableview
import UIKit
import Foundation
import Alamofire
import SwiftyJSON
import Parse
class VCrestlist: UITableViewController{
let PageSize = 80
var items:[RestsModel] = []
var isLoading = false
var letter = "ALL"
var online = false
var loaded = false
var bigviewforact:UIView = UIView(frame: UIScreen.main.bounds)
#IBOutlet var MyFooterView : UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.MyFooterView.isHidden = true
createButtons()
// Load custom Xib RestCell
let nib = UINib(nibName: "RestCell", bundle: nil)
// register cell identifier with custom Xib RestCell
self.tableView.register(nib, forCellReuseIdentifier: "Cell")
tableView.dataSource = self
loadSegment(0, size: self.PageSize,argletter:"ALL",online:self.online)
self.ButtonsScrollView.isScrollEnabled = true
}
class DataManager {
func requestData(_ offset:Int, size:Int,letter:String,online:Bool, listener:#escaping ([RestsModel]) -> ()) {
DispatchQueue.global(qos: .background).async {
var letra = ""
print("el offest es \(offset) y el size es \(size)")
if (letter != "") {
letra = letter
} else {
letra = "ALL"
}
let cart = Cart.sharedInstance
Alamofire.request("https://www.getmedata.com/rests.php", parameters: ["offset": "\(offset)","size":"\(size)","letra":"\(letra)","online":"\(online)"]).authenticate(usingCredential: cart.credential).responseJSON() {
response in
if(response.result.value != nil) {
let jsonObj = JSON(response.result.value!);
let rests = jsonObj as JSON
// print(jsonObj);
//generate items
if let restsarray = rests["rests"].arrayValue as [JSON]? {
var arr = [RestsModel]()
//3
for restDict in restsarray {
let restName: String? = restDict["nombre"].stringValue
let restLOGO: String? = restDict["logo"].stringValue
let detURL: String? = restDict["url"].stringValue
let detProvincia: String? = restDict["provincia"].stringValue
let detHorario: String? = restDict["horario"].stringValue
let detDireccion: String? = restDict["direccion"].stringValue
let detTipoComida: String? = restDict["tipo_comida"].stringValue
let detTelefono: String? = restDict["telefono"].stringValue
let detidRest: String? = restDict["id"].stringValue
let detalleDelivery: String? = restDict["alldelivery"].stringValue
let detalleOrderOnline: String? = restDict["orderonline"].stringValue
let detalleReservaOnline: String? = restDict["reservasonline"].stringValue
let dethasSchedule: Bool? = restDict["hasSchedule"].boolValue
let detopenNow: Bool? = restDict["opennow"].boolValue
let detscheduleToday: String? = restDict["scheduleToday"].stringValue
let detscheduleTodayLiteral: String? = restDict["scheduleTodayLiteral"].stringValue
let emp_instagram: String? = restDict["emp_instagram"].stringValue
let emp_e_orderonline: String? = restDict["emp_e_orderonline"].stringValue
let emp_e_reservasonline: String? = restDict["emp_e_reservasonline"].stringValue
let emp_e_kids: String? = restDict["emp_e_kids"].stringValue
let emp_e_pickup: String? = restDict["emp_e_pickup"].stringValue
let emp_e_delivery: String? = restDict["emp_e_delivery"].stringValue
let emp_e_wifi: String? = restDict["emp_e_wifi"].stringValue
let emp_e_valet: String? = restDict["emp_e_valet"].stringValue
let emp_e_exterior: String? = restDict["emp_e_exterior"].stringValue
let emp_e_happyhour: String? = restDict["emp_e_happyhour"].stringValue
let emp_e_desayuno: String? = restDict["emp_e_desayuno"].stringValue
let emp_e_fumar: String? = restDict["emp_e_fumar"].stringValue
let emp_e_vinos: String? = restDict["emp_e_vinos"].stringValue
let emp_e_bar: String? = restDict["emp_e_bar"].stringValue
let emp_e_games: String? = restDict["emp_e_games"].stringValue
let rest = RestsModel(name: restName!,image:restLOGO!,detailURL:detURL!,provincia:detProvincia!,tipocomida:detTipoComida!,idRest:detidRest!,hasSchedule: dethasSchedule!,scheduleToday: detscheduleToday!,scheduleTodayLiteral: detscheduleTodayLiteral!,openNow: detopenNow!,allDelivery: detalleDelivery!,orderonline: detalleOrderOnline!,reservaonline: detalleReservaOnline!, instagram: emp_instagram!, emp_e_kids: emp_e_kids!, emp_e_pickup: emp_e_pickup!, emp_e_delivery: emp_e_delivery!, emp_e_wifi: emp_e_wifi!, emp_e_valet: emp_e_valet!, emp_e_exterior: emp_e_exterior!, emp_e_happyhour: emp_e_happyhour!, emp_e_desayuno: emp_e_desayuno!, emp_e_fumar: emp_e_fumar!, emp_e_vinos: emp_e_vinos!, emp_e_bar: emp_e_bar!, emp_e_games: emp_e_games!, horario: detHorario!, direccion: detDireccion! ,telefono: detTelefono!)
arr.append(rest)
}
print(arr)
//call listener in main thread
DispatchQueue.main.async {
listener(arr)
}
}
}
}
}
///
}
}
func loadSegment(_ offset:Int, size:Int,argletter:String,online:Bool) {
if (self.loaded == false) {
let act:UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
bigviewforact.addSubview(act)
act.center = bigviewforact.center
self.view.addSubview(bigviewforact)
self.view.bringSubview(toFront: bigviewforact)
act.hidesWhenStopped = true
act.startAnimating()
//self.bigviewforact.removeFromSuperview()
self.loaded = true
}
//if (!self.isLoading) {
// self.isLoading = true
//self.MyFooterView.isHidden = (offset==0) ? true : false
let manager = DataManager()
manager.requestData(offset, size: size,letter:argletter,online:online,
listener: {(items:[RestsModel]) -> () in
/*
Add Rows at indexpath
*/
for item in items {
self.tableView.beginUpdates()
let row = self.items.count
let indexPath = IndexPath(row:row,section:0)
self.items += [item]
self.tableView?.insertRows(at: [indexPath], with: UITableViewRowAnimation.fade)
self.tableView.endUpdates()
}
self.bigviewforact.removeFromSuperview()
self.isLoading = false
self.MyFooterView.isHidden = true
}
)
// }
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == items.count-70 {
loadSegment(items.count, size: PageSize,argletter:self.letter,online:self.online)
}
}
// MARK: Table view data source
override func numberOfSections(in tableView: UITableView?) -> Int {
return 1
}
override func tableView(_ tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView?, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 85;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : RestCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! RestCell
// Pass data to Cell :) clean the mess at the View Controller ;)
cell.restData = items[indexPath.row]
cell.tag = indexPath.row
return cell
}
}
Don't insert each item into UITableView. Insert all of them together.
var indexPathes: [IndexPath] = []
var newItems: [RestsModel] = []
for item in items {
let row = self.items.count
let indexPath = IndexPath(row:row,section:0)
newItems.append(item)
indexPathes.append(indexPath)
}
self.items.append(contentsOf: newItems)
self.tableView.beginUpdates()
self.tableView?.insertRows(at: indexPathes, with: UITableViewRowAnimation.fade)
self.tableView.endUpdates()
I am implementing a search bar into my project but I am being presented with the below error.
reason: 'Can't use in/contains operator with collection wellpleased.attendees.UserData(firstname: "Ben", lastname: "Delonge", fullname: "Ben Delonge", company: "AllStar.com", jobtitle: "Business Development Manager", image: "6.jpg") (not a collection)'
I have done plenty of searching around the NSPredicate but cannot seem to prevent this crashing.
I am using the code below, any assistance resolving this would be much appreciated.
class attendees: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var tableData = ""
var value:String!
var searchString: String = ""
var dataSource: [UserData] = []
struct UserData {
var firstname: String
var lastname: String
var fullname: String
var company: String
var jobtitle: String
var image: String
}
var filteredAppleProducts = [String]()
var resultSearchController = UISearchController()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
print(value)
searchBar.delegate = self
self.tableView.reloadData()
let nib = UINib(nibName: "vwTblCell2", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell2")
}
override func viewDidAppear(_ animated: Bool) {
getTableData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if filteredAppleProducts != []{
return self.filteredAppleProducts.count
}
else
{
if searchString != "[]" {
return self.dataSource.count
}else {
return 0
}
}
}
// 3
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell2: TblCell2 = self.tableView.dequeueReusableCell(withIdentifier: "cell2") as! TblCell2
print(filteredAppleProducts)
if filteredAppleProducts != []{
cell2.nameLabel.text = self.filteredAppleProducts[indexPath.row]
return cell2
}
else
{
if searchString != "[]"{
cell2.nameLabel.text = self.dataSource[indexPath.row].fullname
cell2.companyLabel.text = self.dataSource[indexPath.row].company
cell2.jobTitleLabel.text = self.dataSource[indexPath.row].jobtitle
let url = URL(string: "https://www.asmserver.co.uk/wellpleased/backend/profileimages/\(self.dataSource[indexPath.row].image)")
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell2.userImage.image = UIImage(data: data!)
}
return cell2
}
}
// 4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
// 5
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
func updateSearchResults(){
self.filteredAppleProducts.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchString)
let array = (self.dataSource as NSArray).filtered(using: searchPredicate)
self.filteredAppleProducts = array as! [String]
self.tableView.reloadData()
print(filteredAppleProducts)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print("searchText \(searchText)")
print(filteredAppleProducts)
searchString = searchText
updateSearchResults()
}
func getTableData(){
self.dataSource.removeAll()
let defaults = UserDefaults()
let userid = defaults.string(forKey: "id")
let url = NSURL(string: "https://www.******.co.uk/wellpleased/backend/searchattendees.php?userid=\(userid!)&eventid=\(value!)")
print(url)
let task = URLSession.shared.dataTask(with: url as! URL) { (data, response, error) -> Void in
if let urlContent = data {
do {
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [[String:AnyObject]] {
var i = 0
while i < jsonResult.count {
self.dataSource.append(UserData(firstname:"\(jsonResult[i]["firstname"]! as! String)", lastname: "\(jsonResult[i]["lastname"]! as! String)", fullname:"\(jsonResult[i]["fullname"]! as! String)", company: "\(jsonResult[i]["company"]! as! String)", jobtitle:"\(jsonResult[i]["jobtitle"]! as! String)", image:"\(jsonResult[i]["image"]! as! String)"))
i = i + 1
}
}
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
self.tableView.isUserInteractionEnabled = true
}
task.resume()
}
}
I have also tired:
let searchPredicate = NSPredicate(format: "fullname CONTAINS[c] %#", searchString as String)
which returns the error:
this class is not key value coding-compliant for the key fullname
NSPredicate is a Cocoa feature that lives in the Objective-C world. It's never going to work on an array of UserData because UserData is a Swift struct — and Objective-C cannot see a Swift struct at all (and even if it could, it certainly can't see any type namespaced inside a class, as your UserData is).
You would have an easy time of this if you simply used the built-in Swift filter method to filter the dataSource array. For example (if this is what you're trying to do):
let array = self.dataSource.filter{$0.fullname.contains(searchString)}
In Swift 3, you can combine NSArray with NSPredicate like this:
let searchPredicate = NSPredicate(format: "%K CONTAINS[c] %#", "fullname",searchString)
let array = NSArray(array: self.dataSource).filtered(using: searchPredicate)
I have populated a table using json data from a remote server.
I am now trying to add a search bar which will filter the results.
The issue I am facing is that I am storing the json data in several arrays.
name, company, job title etc
This means that when the user searches only the name array is filtered and displayed in the table correctly, the other information is out of sync as it remains unfiltered.
Am I approaching this in the correct way?
class attendees: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var tableData = ""
var value:String!
var searchString = ""
var firstname: [String] = []
var lastname: [String] = []
var fullname: [String] = []
var company: [String] = []
var jobtitle: [String] = []
var image: [String] = []
var filteredAppleProducts = [String]()
var resultSearchController = UISearchController()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
print(value)
searchBar.delegate = self
self.tableView.reloadData()
let nib = UINib(nibName: "vwTblCell2", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell2")
}
override func viewDidAppear(_ animated: Bool) {
getTableData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if filteredAppleProducts != []{
return self.filteredAppleProducts.count
}
else
{
if searchString != "[]" {
return self.firstname.count
}else {
return 0
}
}
}
// 3
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell2: TblCell2 = self.tableView.dequeueReusableCell(withIdentifier: "cell2") as! TblCell2
print(filteredAppleProducts)
if filteredAppleProducts != []{
cell2.nameLabel.text = self.filteredAppleProducts[indexPath.row]
return cell2
}
else
{
if searchString != "[]"{
cell2.nameLabel.text = "\(self.firstname[indexPath.row]) \(self.lastname[indexPath.row])"
cell2.companyLabel.text = self.company[indexPath.row]
cell2.jobTitleLabel.text = self.jobtitle[indexPath.row]
let url = URL(string: "https://www.asmserver.co.uk/wellpleased/backend/profileimages/\(self.image[indexPath.row])")
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell2.userImage.image = UIImage(data: data!)
}
return cell2
}
}
// 4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
// 5
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
func updateSearchResults(){
self.filteredAppleProducts.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchString)
let array = (self.fullname as NSArray).filtered(using: searchPredicate)
self.filteredAppleProducts = array as! [String]
self.tableView.reloadData()
print(filteredAppleProducts)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print("searchText \(searchText)")
print(filteredAppleProducts)
searchString = searchText
updateSearchResults()
}
func getTableData(){
self.firstname.removeAll()
self.lastname.removeAll()
self.fullname.removeAll()
self.company.removeAll()
self.jobtitle.removeAll()
self.image.removeAll()
let defaults = UserDefaults()
let userid = defaults.string(forKey: "id")
let url = NSURL(string: "https://www.asmserver.co.uk/wellpleased/backend/searchattendees.php?userid=\(userid!)&eventid=\(value!)")
print(url)
let task = URLSession.shared.dataTask(with: url as! URL) { (data, response, error) -> Void in
if let urlContent = data {
do {
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [[String:AnyObject]] {
var i = 0
while i < jsonResult.count {
self.firstname.append(jsonResult[i]["firstname"]! as! String)
self.lastname.append(jsonResult[i]["lastname"]! as! String)
let fname = jsonResult[i]["firstname"]! as! String
let lname = jsonResult[i]["lastname"]! as! String
let fullname1 = "\(fname) \(lname)"
self.fullname.append(fullname1)
self.company.append(jsonResult[i]["company"]! as! String)
self.jobtitle.append(jsonResult[i]["jobtitle"]! as! String)
self.image.append(jsonResult[i]["image"]! as! String)
i = i + 1
}
}
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
self.tableView.isUserInteractionEnabled = true
}
task.resume()
}
}
Use a struct or class for the data. This way it'll be easier to keep track of the data, and in any case it looks like you don't have any good reason to keep track of seven different arrays.
As an example:
struct Data {
var firstName: String
var lastName: String
var fullName: String
var company: String
var jobTitle: String
var image: String
}
And populate just the one array:
var dataSource: [Data] = []
Access with property name, instead of arrayName[index]:
let name = dataSource[index].firstName
Please see screenshot. There is a repliesTableView, replyTextField and replyButtonin ViewController. repliesTableView cell is called ReplyCell. In ReplyCell there is a commentTableView to list all comments for that reply and a textfField, a commentButton to add new comments.
I have problem when add new replies and new comments. I guess I need to make comments array in ReplyCell empty when I click the Reply button. How can I make this happen? I have no idea how to access comments arrayfrom the root ViewController.
Exact problems: fter clicking commentButton, all comments in every cell doubled. After clicking replyButton, comments went to wrong cell.
Code:
import UIKit
import Firebase
class TopicForumVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var topicNameLabel: UILabel!
#IBOutlet weak var replyNumberLabel: UILabel!
#IBOutlet weak var repliesTableView: UITableView!
#IBOutlet weak var replyTextField: UITextField!
var topicName:String?
var firstKey:String?
var secondKey:String?
var replies = [String]()
var replyButtonTapped = false
override func viewDidLoad() {
super.viewDidLoad()
repliesTableView.delegate = self
repliesTableView.dataSource = self
replyTextField.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
topicNameLabel.text = self.topicName
loadReplies()
}
func loadReplies() {
self.replies = []
DataService.ds.Categories_Base.child(self.firstKey!).child("Topics").observe(.value, with:{(snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots {
if let topicDict = snap.value as? Dictionary<String,AnyObject> {
if let topic = topicDict["text"] as? String {
if topic == self.topicName {
self.secondKey = snap.key
UserDefaults.standard.setValue(snap.key, forKey: Key_SecondKey)
if let replyDict = topicDict["replies"] as? Dictionary<String,AnyObject> {
for eachDict in replyDict {
if let textDict = eachDict.value as? Dictionary<String,AnyObject> {
if let reply = textDict["text"] as? String {
self.replies.append(reply)
self.replyNumberLabel.text = String(self.replies.count)
}
}
}
}
}
}
}
}
self.repliesTableView.reloadData()
}
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return replies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "ReplyCell") as? ReplyCell {
let reply = replies[indexPath.row]
cell.configureReplyCell(reply: reply)
return cell
} else {
return UITableViewCell()
}
}
#IBAction func replyButtonTapped(_ sender: Any) {
replyButtonTapped = true
if let reply = replyTextField.text, reply != "" {
self.replies = []
DataService.ds.Categories_Base.child(self.firstKey!).child("Topics").child(self.secondKey!).child("replies").childByAutoId().child("text").setValue(reply)
self.repliesTableView.reloadData()
let i = replies.count
for n in 0..<i {
let indexPath = IndexPath(row: n, section: 1)
let cell = repliesTableView.cellForRow(at: indexPath) as! ReplyCell
cell.comments = []
cell.repliesToReplyTableView.reloadData()
}
self.replyTextField.text = ""
self.replyButtonTapped = false
}
}
}
import UIKit
import Firebase
class ReplyCell: UITableViewCell,UITableViewDataSource,UITableViewDelegate, UITextFieldDelegate {
#IBOutlet weak var replyTextView: UITextView!
#IBOutlet weak var repliesToReplyTableView: UITableView!
#IBOutlet weak var commentTextField: UITextField!
var reply:String?
var comments = [String]()
var replyKey:String?
override func awakeFromNib() {
super.awakeFromNib()
self.comments = []
repliesToReplyTableView.delegate = self
repliesToReplyTableView.dataSource = self
commentTextField.delegate = self
loadComments()
}
func configureReplyCell(reply:String) {
self.reply = reply
self.replyTextView.text = self.reply
}
func loadComments() {
self.comments = []
if let firstKey = UserDefaults.standard.value(forKey: Key_FirstKey) as? String, let secondKey = UserDefaults.standard.value(forKey: Key_SecondKey) as? String {
DataService.ds.Categories_Base.child(firstKey).child("Topics").child(secondKey).child("replies").observe(.value, with:{(snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots {
if let replyDict = snap.value as? Dictionary<String,AnyObject> {
if let reply = replyDict["text"] as? String {
if reply == self.reply {
self.replyKey = snap.key
DataService.ds.Categories_Base.child(firstKey).child("Topics").child(secondKey).child("replies").child(snap.key).child("comments").observe(.value, with: { (commentSnapshot) in
if let commentSnapshots = commentSnapshot.children.allObjects as? [FIRDataSnapshot] {
for commentSnap in commentSnapshots {
if let commentDict = commentSnap.value as? Dictionary<String,AnyObject> {
if let comment = commentDict["text"] as? String {
self.comments.append(comment)
}
}
}
}
self.repliesToReplyTableView.reloadData()
})
}
}
}
}
}
})
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let commentCell = tableView.dequeueReusableCell(withIdentifier:"CommentCell")
commentCell?.textLabel?.text = comments[indexPath.row]
return commentCell!
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func commentBtnPressed(_ sender: Any) {
if let comment = commentTextField.text, comment != "" {
self.comments = []
if let firstKey = UserDefaults.standard.value(forKey: Key_FirstKey) as? String, let secondKey = UserDefaults.standard.value(forKey: Key_SecondKey) as? String {
DataService.ds.Categories_Base.child(firstKey).child("Topics").child(secondKey).child("replies").child(self.replyKey!).child("comments").childByAutoId().child("text").setValue(comment)
if let myViewController = parentViewController as? TopicForumVC {
// myViewController.repliesTableView.reloadData()
myViewController.replies = []
}
self.repliesToReplyTableView.reloadData()
self.commentTextField.text = ""
self.replyKey = ""
}
}
}
I don't really know the exact circumstances of what you're building but there are two ideas that may offer some guidance.
1) If your table is displaying content from a data source then you will likely have some kind of reference. E.g. when loading the cells (in this case CustomCell) you'll do something like get the index of the cell and get the same index from the data, and put that data in the cells content. If that's the case, all you have to do on the button click is use tableview.cellForRowAtIndexPath with your sender object, and then remove the array from the data source, e.g. tableDataSource[index] = nil and reload the tableView.
2) If you have a stored property on the CustomCell that you've add specifically for storing this array, then you'd cast the sender object to CustomCell and remove the property, as in Kim's answer.
Hope this helps, but without more information it's kind of hard to tell.
let cell = tableview.cellForRowAtIndexPath(...) as? CustomCell
if cell != nil {
let arr = cell.array
}
BTW: I would re-think storing your array in the cell..