The orders are being stored as Order objects: let orders = [Order]()
The idea is to call my API every second and when a new cell is created, the table should show the new cell.
var timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: "GetOrders", userInfo: nil, repeats: true)
this code does refresh my function to get data but repeats the cell !!
so in the beginning of GetOrders function I erase the array then upload it with new array from API.
func GetOrders (){
orders = []
but the code crushes when the new order is deleted from database. it shows int he table. When I click on it to returns ' index out of range' because of this function
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let order = orders[indexPath.row]
guard orders.count > indexPath.row else {
print("Index out of range")
return
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var viewController = storyboard.instantiateViewController(withIdentifier: "viewControllerIdentifer") as! OrderDetailsController
viewController.passedValue = order.id
self.present(viewController, animated: true , completion: nil)
}
UPDATE
func GetOrders (){
orders = []
print("hi")
let urlStr = "api/orders"
let url = URL(string: urlStr)
let user = "api"
let password = "Apipass"
var headers: HTTPHeaders = [
"Authorization": "Basic YXBpdXNlcjpBcGlBdXRoUGFzczIwMTchQCM="
]
Alamofire.request(url!, method: .get ,encoding: URLEncoding.default, headers: headers).responseJSON { response in
if let value: AnyObject = response.result.value as AnyObject? {
//Handle the results as JSON
let data = JSON(value)
for (key,subJson):(String, JSON) in data[0] {
//Do something you want
let logo = subJson["family"]["logo"]
let logoString = "img/\(logo)"
if let date = subJson["family"]["updated_at"].string {
print(date)
if let cleintName = subJson["client"]["name"].string {
let info = Order(shopname: shopname, shopaddress: shopaddr, clientName: cleintName, ClientAddress: clientAddres, PerferTime: time, Cost: subtotal , date : time , Logo : logoString ,id : id)
self.orders.append(info)
}
self.tableview.reloadData()
}
}
Have you tried going on the mainthread?
DispatchQueue.main.async {
self.tableView.reloadData()
}
Related
My requirement : I will be having a list of chat details in a table view.On top of table view ,there will be a search functionality using text field.based on unique id of user, search should get done.if there is no chat with the unique id, which the user entered,then it has to redirect to another screen which is called chatcreatepage. when ever we are searching chat, we will be using an api called FIND API and in that FIND API there is a chat dictionary,if it is null,then create chat will get called.If that chat dictionary is not nil then need to display that chat details in chat list table view. When the chat list page is loading then ,we will be calling Chat list Api.when we are searching the chat by entering the unique id in textfield,we will be getting the corresponding details of that entered unique id & that unique id details we have to show in the table view.
This is the task and i have done till the chat list showing in the table.I am really not aware of this search result showing after calling the FIND API.If anyone helps me to solve it, would be really great.Thank in advance.I am providing the code below.
import UIKit
import Alamofire
import SwiftyJSON
import SDWebImage
class ChatlistViewController: UIViewController{
var pro = [[String:Any]]()
var dict:[String:Any]!
var idd = ""
var id = ""
var chatt:Dictionary = [String:Any]()
var searchActive : Bool = false
var filtered:[String] = []
var data:[String] = []
#IBOutlet weak var search-text: UITextField!
#IBOutlet weak var chatlisttable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
apical()
}
func apical(){
let acce:String = UserDefaults.standard.string(forKey: "access-tokenn")!
print(acce)
let headers:HTTPHeaders = ["Authorization":"Bearer \(acce)","Content-Type":"application/X-Access-Token"]
Alamofire.request(Constants.Chatlist, method: .get, encoding: URLEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success:
print(response)
if response.result.value != nil{
var maindictionary = NSDictionary()
maindictionary = response.result.value as! NSDictionary
print(maindictionary)
var userdata = NSDictionary()
userdata = maindictionary.value(forKey: "data") as! NSDictionary
var productsdetails = [[String:Any]]()
productsdetails = userdata.value(forKey: "chat") as! [[String:Any]]
self.pro = productsdetails
print(self.pro)
self.chatlisttable.reloadData()
}else{
let Alertcontroller = UIAlertController(title: "Alert", message: "No data found ", preferredStyle: .alert)
let CancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
Alertcontroller.addAction(CancelAction)
self.present(Alertcontroller, animated: true, completion: nil)
}
break
case .failure(let error):
print(error)
}
}
}
func searchapicall(){
idd = searchtext.text!
let acce:String = UserDefaults.standard.string(forKey: "access-tokenn")!
print(acce)
let headers:HTTPHeaders = ["Authorization":"Bearer \(acce)","Content-Type":"application/X-Access-Token"]
print((Constants.Chatlistsearch)+(idd))
Alamofire.request((Constants.Chatlistsearch+idd), method: .get, encoding: URLEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success:
//print(response)
if response.result.value != nil{
var maindictionary = NSDictionary()
maindictionary = response.result.value as! NSDictionary
var chat:Dictionary = maindictionary.value(forKey: "data") as! [String:Any]
var chattt:Dictionary = chat["chat"] as! [String:Any]
if (chattt != nil) {
print("Find Action")
self.chatt = chat["user"] as! [String:Any]
print(self.chatt)
//var uniqued:String = self.chatt["unique_id"] as! String
}else{
let viewc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ChatViewController") as? ChatViewController
self.navigationController?.pushViewController(viewc!, animated: true)
}
}else{
let Alertcontroller = UIAlertController(title: "Alert", message: "No data found on this unique id", preferredStyle: .alert)
let CancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
Alertcontroller.addAction(CancelAction)
self.present(Alertcontroller, animated: true, completion: nil)
}
break
case .failure(let error):
print(error)
}
}
}
}
extension ChatlistViewController: UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.searchapicall()
return true
}
}
extension ChatlistViewController: UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (searchActive == false){
return self.pro.count
}else{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = chatlisttable.dequeueReusableCell(withIdentifier: "ChatlistTableViewCell", for: indexPath) as! ChatlistTableViewCell
if (searchActive == false){
dict = pro[indexPath.row]
var recepient = dict["recipient"] as! [String:Any]
print(recepient)
var name = recepient["name"] as! String
print(name)
id = recepient["unique_id"] as! String
print(id)
var image = recepient["avatar"] as! String
print(image)
cell.namelbl.text = name
cell.idlbl.text = id
cell.imageView!.sd_setImage(with: URL(string:image), placeholderImage: UIImage(named: "Mahi.png"))
}else{
cell.namelbl.text = chatt["name"] as! String
cell.idlbl.text = chatt["unique_id"] as! String
}
return cell
self.chatlisttable.reloadData()
}
}
//Response format
{
"success": 1,
"status": 200,
"data": {
"user": {
"id": 3,
"unique_id": "10002",
"name": "nani",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/AkgcUFF3QIejMhZuLF4OXnSFHjxNAOo4FuXV3Mgi.jpeg"
},
"chat": null
}
}
You have to use UISearchBar and in call your api in delegate method of searchbar func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String).
For reference use this https://guides.codepath.com/ios/Search-Bar-Guide
I'm having a problem regarding a feature where You can delete a cell and so delete and event using an Alamofire JSON request.
When I swipe the cell and click delete, the app crashes, but the event get deleted successfully and with no errors, in facts on Laravel side I get the event deleted.
I tried everything, but I really can't figure out how to fix the crash.
Can someone help me please?
here is my .Swift code:
import UIKit
import Alamofire
class EventViewController: UITableViewController {
#objc var transition = ElasticTransition()
#objc let lgr = UIScreenEdgePanGestureRecognizer()
#objc let rgr = UIScreenEdgePanGestureRecognizer()
let rc = UIRefreshControl()
#IBOutlet weak var myTableView: UITableView!
var myTableViewDataSource = [NewInfo]()
let url = URL(string: "http://ns7records.com/staffapp/api/events/index")
override func viewDidLoad() {
super.viewDidLoad()
loadList()
// Add Refresh Control to Table View
if #available(iOS 10.0, *) {
tableView.refreshControl = rc
} else {
tableView.addSubview(rc)
}
// Configure Refresh Control
rc.addTarget(self, action: #selector(refreshTableData(_:)), for: .valueChanged)
let attributesRefresh = [kCTForegroundColorAttributeName: UIColor.white]
rc.attributedTitle = NSAttributedString(string: "Caricamento ...", attributes: attributesRefresh as [NSAttributedStringKey : Any])
DispatchQueue.main.async {
}
// MENU Core
// customization
transition.sticky = true
transition.showShadow = true
transition.panThreshold = 0.3
transition.transformType = .translateMid
// menu// gesture recognizer
lgr.addTarget(self, action: #selector(MyProfileViewController.handlePan(_:)))
rgr.addTarget(self, action: #selector(MyProfileViewController.handleRightPan(_:)))
lgr.edges = .left
rgr.edges = .right
view.addGestureRecognizer(lgr)
view.addGestureRecognizer(rgr)
}
#objc private func refreshTableData(_ sender: Any) {
// Fetch Table Data
//myTableViewDataSource.removeAll()
tableView.reloadData()
loadList()
}
func loadList(){
var myNews = NewInfo()
// URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
//
// })
let task = URLSession.shared.dataTask(with:url!) {
(data, response, error) in
if error != nil
{
print("ERROR HERE..")
}else
{
do
{
if let content = data
{
let myJson = try JSONSerialization.jsonObject(with: content, options: .mutableContainers)
//print(myJson)
if let jsonData = myJson as? [String : Any]
{
if let myResults = jsonData["data"] as? [[String : Any]]
{
//dump(myResults)
for value in myResults
{
if let myTitle = value["title"] as? String
{
//print(myTitle)
myNews.displayTitle = myTitle
}
if let myLocation = value["local"] as? String
{
myNews.location = myLocation
}
if let myDate = value["date"] as? String
{
myNews.date = myDate
}
if let myDescription = value["description"] as? String
{
myNews.description = myDescription
}
if let myCost = value["cost"] as? String
{
myNews.cost = myCost
}
if let myNumMembers = value["num_members"] as? String
{
myNews.num_members = myNumMembers
}
if let myNumMembers_conf = value["num_members_confirmed"] as? String
{
myNews.num_members_confirmed = myNumMembers_conf
}
if let myStartEvent = value["time_start"] as? String
{
myNews.startEvent = myStartEvent
}
if let myEndEvent = value["time_end"] as? String
{
myNews.endEvent = myEndEvent
}
if let myId = value["id"] as? Int
{
myNews.idEvent = myId
}
//x img
// if let myMultimedia = value["data"] as? [String : Any]
// {
if let mySrc = value["event_photo"] as? String
{
myNews.event_photo = mySrc
print(mySrc)
}
self.myTableViewDataSource.append(myNews)
}//end loop
dump(self.myTableViewDataSource)
DispatchQueue.main.async
{
self.tableView.reloadData()
self.rc.endRefreshing()
}
}
}
}
}
catch{
}
}
}
task.resume()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)->CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myTableViewDataSource.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "reuseCell", for: indexPath)
let myImageView = myCell.viewWithTag(11) as! UIImageView
let myTitleLabel = myCell.viewWithTag(12) as! UILabel
let myLocation = myCell.viewWithTag(13) as! UILabel
let DateLabelCell = myCell.viewWithTag(14) as! UILabel
let numMembLabel = myCell.viewWithTag(15) as! UILabel
let numMembConfLabel = myCell.viewWithTag(16) as! UILabel
myTitleLabel.text = myTableViewDataSource[indexPath.row].displayTitle
myLocation.text = myTableViewDataSource[indexPath.row].location
DateLabelCell.text = myTableViewDataSource[indexPath.row].date
numMembLabel.text = myTableViewDataSource[indexPath.row].num_members
numMembConfLabel.text = myTableViewDataSource[indexPath.row].num_members_confirmed
if let imageURLString = myTableViewDataSource[indexPath.row].event_photo,
let imageURL = URL(string: AppConfig.public_server + imageURLString) {
myImageView.af_setImage(withURL: imageURL)
}
return myCell
}
//per passare da un viewcontroller a detailviewcontroller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? EventDetailViewController {
destination.model = myTableViewDataSource[(tableView.indexPathForSelectedRow?.row)!]
// Effetto onda
let vc = segue.destination
vc.transitioningDelegate = transition
vc.modalPresentationStyle = .custom
}
//menu
if let vc = segue.destination as? MenuViewController{
vc.transitioningDelegate = transition
vc.modalPresentationStyle = .custom
//endmenu
}
}
//menu slide
#objc func handlePan(_ pan:UIPanGestureRecognizer){
if pan.state == .began{
transition.edge = .left
transition.startInteractiveTransition(self, segueIdentifier: "menu", gestureRecognizer: pan)
}else{
_ = transition.updateInteractiveTransition(gestureRecognizer: pan)
}
}
//endmenuslide
////ximg
func loadImage(url: String, to imageView: UIImageView)
{
let url = URL(string: url )
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let data = data else
{
return
}
DispatchQueue.main.async
{
imageView.image = UIImage(data: data)
}
}.resume()
}
/// star to: (x eliminare row e x muove row)
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObjTemp = myTableViewDataSource[sourceIndexPath.item]
myTableViewDataSource.remove(at: sourceIndexPath.item)
myTableViewDataSource.insert(movedObjTemp, at: destinationIndexPath.item)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete){
// print(parameters)
let idEvent = (myTableViewDataSource[indexPath.item].idEvent)
let parameters = [
// "id": UserDefaults.standard.object(forKey: "userid")! ,
"id" : idEvent,
] as [String : Any]
let url = "http://www.ns7records.com/staffapp/public/api/deleteevent"
print(url)
Alamofire.request(url, method:.post, parameters:parameters,encoding: JSONEncoding.default).responseJSON { response in
switch response.result {
case .success:
print(response)
let JSON = response.result.value as? [String : Any]
//self.myTableView.reloadData()
let alert = UIAlertController(title: "Yeah!", message: "Evento modificato con successo!", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
// let data = JSON! ["data"] as! NSDictionary
if let jsonData = JSON as? [String : Any]
{
print(jsonData)
self.myTableViewDataSource.remove(at : indexPath.item)
self.myTableView.deleteRows(at: [indexPath], with: .automatic)
let indexPath = IndexPath(item: 0, section: 0)
//self.myTableView.deleteRows(at: [indexPath], with: .fade)
//self.myTableView.reloadData()
// }
// }
//}
}
case .failure(let error):
print(error)
let alert = UIAlertController(title: "Aia", message: "Non puoi cancellare questo evento!", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
}
#IBAction func EditButtonTableView(_ sender: UIBarButtonItem) {
self.myTableView.isEditing = !self.myTableView.isEditing
sender.title = (self.myTableView.isEditing) ? "Done" : "Edit"
}
/// end to: (x eliminare row e x muove row)
}
// MARK: -
// MARK: UITableView Delegate
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
My tableView does not show the data. I am fetching the data through api and save it into separate class with initializers. But it does not the show on the tableView. How to resolve this issue. I am new to iOS. I know there is only one line of code problem somewhere.
I call api in viewDidLoad method.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
//fetch all expected visitor data
self.apiExpectedVisitor(strURL: urlViewExpectedVisitors)
self.expectedTableView.reloadData()
}
Function of API Method
func apiExpectedVisitor(strURL: String)
{
fetchedExpectedData = []
//URL
let myURL = URL(string: strURL)
//URL Request
let request = NSMutableURLRequest(url: myURL!)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
let token = "Bearer " + strToken
request.addValue(token, forHTTPHeaderField: "Authorization")
let postTask = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
print(response!)
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: [Any]] {
print("POST Method :\(json)")
DispatchQueue.main.async {
for expectedVisitors in json["expected_visitors"]!
{
let eachData = expectedVisitors as! [String: Any]
let id = eachData["id"] as! Int
let name = "\(String(describing: eachData["name"]))"
let email = "\(String(describing: eachData["email"]))"
let phone = eachData["phone"] as! String
let verification_code = "\(String(describing: eachData["expected_visitor_verification_code"]))"
let qr_code = eachData["expected_visitor_qr_code"] as? String
let isVisited = eachData["is_visited"] as! Int
let company_id = eachData["company_id"] as! Int
let purpose = "\(String(describing: eachData["purpose"]))"
let meeting_date = eachData["meeting_date"] as! String
let meeting_time = eachData["meeting_time"] as! String
let created_at = eachData["created_at"] as! String
let updated_at = eachData["updated_at"] as! String
//Date.formatter(createdDate: createdDate)
if let department_id = eachData["department_id"] as? Int, let employee_id = eachData["employee_id"] as? Int, let location_id = eachData["location_id"] as? Int, let image = eachData["image"] as? String, let duration = eachData["duration"] as? String {
fetchedExpectedData.append(FetchedAllExpectedVisitors.init(id: id, name: name, email: email, phone: phone, department_id: department_id, employee_id: employee_id, location_id: location_id, image: image, verification_code: verification_code, qr_code: qr_code!, isVisited: isVisited, company_id: company_id, purpose: purpose, meeting_date: meeting_date, meeting_time: meeting_time, duration: duration, created_at: created_at, updated_at: updated_at))
self.expectedTableView.reloadData()
}
}
}
}
} catch let error {
print(error.localizedDescription)
}
}
postTask.resume()
}
TableView DataSource and Delegate Methods
func numberOfSections(in tableView: UITableView) -> Int {
return fetchedExpectedData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ShowExpectedCell", for: indexPath) as! ShowExpectedTVCell
cell.lblDate.text = fetchedExpectedData[indexPath.section].created_at
cell.lblVisName.text = fetchedExpectedData[indexPath.section].name
print(fetchedExpectedData[indexPath.section].name)
for i in 0..<fetchedDepttData.count {
let department_id = fetchedDepttData[i].depttID
if fetchedExpectedData[indexPath.section].department_id == department_id
{
cell.lblDeptt.text = fetchedDepttData[i].depttName
}
}
for i in 0..<fetchedEmployeeData.count {
let employee_id = fetchedEmployeeData[i].empID
if fetchedExpectedData[indexPath.section].employee_id == employee_id
{
cell.lblEmpName.text = fetchedEmployeeData[i].name
}
}
return cell
}
Check below points:-
Make sure you registered tableview cell nib and added dataSource and Delegate.
You are reloading tableview after your fetchedExpectedData array filled
Just add the below code in viewDidLoad
expectedTableView.delegate = self
expectedTableView.datasource = self
also check if you have set UITableViewDelegate , UITableViewDataSource in starting of the controller
class Yourviewcontrollername: UIViewController,UITableViewDelegate,UITableViewDataSource
{
//Rest of the code
}
Also put breakpoint in all delegate methods and see if anything hits.
I'm creating a simple chat app, it has a loading screen with a segue to either the login screen if the user is not logged in or directly to his chats if he is. The chats are displayed in a UICollectionView. When I was first testing, I populated it with dummy data which I declared in the class itself, and everything worked fine. Now I am fetching the user's chats from an online database in the Loading Screen, and storing them in an array called user_chats which is declared globally.
I use the following code to populate the UICollectionView :
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// getUserChats()
return user_chats.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("chat_cell" , forIndexPath: indexPath) as! SingleChat
cell.chatName?.text = user_chats[indexPath.row].chat_partner!.name
cell.chatTextPreview?.text = user_chats[indexPath.row].chat_messages!.last!.text
let profile_pic_URL = NSURL(string : user_chats[indexPath.row].chat_partner!.profile_pic!)
downloadImage(profile_pic_URL!, imageView: cell.chatProfilePic)
cell.chatProfilePic.layer.cornerRadius = 26.5
cell.chatProfilePic.layer.masksToBounds = true
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
return view
}()
dividerLineView.translatesAutoresizingMaskIntoConstraints = false
cell.addSubview(dividerLineView)
cell.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-1-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": dividerLineView]))
cell.addSubview(dividerLineView)
cell.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[v0(1)]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": dividerLineView]))
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showChat", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showChat") {
let IndexPaths = self.collectionView!.indexPathsForSelectedItems()!
let IndexPath = IndexPaths[0] as NSIndexPath
let vc = segue.destinationViewController as! SingleChatFull
vc.title = user_chats[IndexPath.row].chat_partner!.name
}
}
DATA FETCH :
func getUserChats() {
let scriptUrl = "*****"
let userID = self.defaults.stringForKey("userId")
let params = "user_id=" + userID!
let myUrl = NSURL(string: scriptUrl);
let request: NSMutableURLRequest = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let data = params.dataUsingEncoding(NSUTF8StringEncoding)
request.timeoutInterval = 10
request.HTTPBody=data
request.HTTPShouldHandleCookies=false
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
if (data != nil) {
do {
var dataString = String(data: data!, encoding: NSUTF8StringEncoding)
var delimiter = "]"
var token = dataString!.componentsSeparatedByString(delimiter)
dataString = token[0] + "]"
print(dataString)
let data_fixed = dataString!.dataUsingEncoding(NSUTF8StringEncoding)
do {
let jsonArray = try NSJSONSerialization.JSONObjectWithData(data_fixed!, options:[])
// LOOP THROUGH JSON ARRAY AND FETCH VALUES
for anItem in jsonArray as! [Dictionary<String, AnyObject>] {
let curr_chat = Chat()
if let chatId = anItem["chatId"] as? String {
curr_chat.id = chatId
}
let friend = Friend()
let user1id = anItem["user1_id"] as! String
let user2id = anItem["user2_id"] as! String
if (user1id == userID) {
if let user2id = anItem["user2_id"] as? String {
friend.id = user2id
}
if let user2name = anItem["user2_name"] as? String {
friend.name = user2name
}
if let user2profilepic = anItem["user2_profile_pic"] as? String {
friend.profile_pic = user2profilepic
}
}
else if (user2id == userID){
if let user1id = anItem["user1_id"] as? String {
friend.id = user1id
}
if let user1name = anItem["user1_name"] as? String {
friend.name = user1name
}
if let user1profilepic = anItem["user1_profile_pic"] as? String {
friend.profile_pic = user1profilepic
}
}
curr_chat.chat_partner = friend
var chat_messages = [Message]()
if let dataArray = anItem["message"] as? [String : AnyObject] {
for (_, messageDictionary) in dataArray {
if let onemessage = messageDictionary as? [String : AnyObject] { let curr_message = Message()
if let messageid = onemessage["message_id"] as? String {
curr_message.id = messageid
}
if let messagedate = onemessage["timestamp"] as? String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = dateFormatter.dateFromString(messagedate)
curr_message.date = date
}
if let messagesender = onemessage["sender"] as? String {
curr_message.sender = messagesender
}
if let messagetext = onemessage["text"] as? String {
curr_message.text = messagetext
}
chat_messages.append(curr_message)
}}
}
curr_chat.chat_messages = chat_messages
user_chats.append(curr_chat)
}
}
catch {
print("Error: \(error)")
}
}
// NSUserDefaults.standardUserDefaults().setObject(user_chats, forKey: "userChats")
}
else {
dispatch_async(dispatch_get_main_queue(), {
let uiAlert = UIAlertController(title: "No Internet Connection", message: "Please check your internet connection.", preferredStyle: UIAlertControllerStyle.Alert)
uiAlert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { action in
self.dismissViewControllerAnimated(true, completion:nil)
}))
self.presentViewController(uiAlert, animated: true, completion: nil)
})
}
} catch _ {
NSLog("error")
}
})
}
The problem is that the collection view is always empty now. I have done some debugging and put a breakpoint inside the first function, and I saw that this method is called when the Loading Screen is still displayed to the user and the chat screen hasn't even been loaded. My suspicion is that this is called before the data is fetched from the internet in the Loading Screen, and as a result the size of the user_chats array is 0. I am used to working with Android and ListView where the ListView are never populated until the parent view is displayed on screen, hence why I am confused. The method which fetches the data from the online database works fine as I have already extensively debugged it, so the problem isn't there.
The best option is to add a completionHandler to your function to be notified when the data is return and/or when the async function is finished executing. The code below is a truncated version of your getUserCharts function with a completionHandler, which returns a true or false when the data is load (You could modify this to return anything you wish). You can read more about closures/ completion handlers https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html or google.
function
func getUserChats(completionHandler: (loaded: Bool, dataNil: Bool) -> ()) -> (){
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
if (data != nil) {
do {
var dataString = String(data: data!, encoding: NSUTF8StringEncoding)
var delimiter = "]"
var token = dataString!.componentsSeparatedByString(delimiter)
dataString = token[0] + "]"
print(dataString)
let data_fixed = dataString!.dataUsingEncoding(NSUTF8StringEncoding)
do {
let jsonArray = try NSJSONSerialization.JSONObjectWithData(data_fixed!, options:[])
// LOOP THROUGH JSON ARRAY AND FETCH VALUES
completionHandler(loaded: true, dataNil: false)
}
catch {
print("Error: \(error)")
}
}
}
else {
//Handle error or whatever you wish
completionHandler(loaded: true, dataNil: true)
}
} catch _ {
NSLog("error")
}
How to use it
override func viewDidLoad() {
getUserChats(){
status in
if status.loaded == true && status.dataNil == false{
self.collectionView?.reloadData()
}
}
}
It sounds like this is an async issue. I'm not sure how your project is setup but you need to call reloadData() on your collection view when the response is returned.
After you have received the data back from the server, and updated the data source for the collection view you need to refresh the collection view (Make sure you are on the main thread, since it is modifying the UI):
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadData()
}
Edit:
Also, I'm not completely sure how you have your project setup, but you could create a delegate for your data fetch, so every time you get something back from the server it calls a delegate method that there are new messages. Your collection view controller would subscribe to that delegate, and every time the that method is called it would reload your collection view.
The Delegate:
protocol ChatsDelegate {
func didUpdateChats(chatsArray: NSArray)
}
In your Data Fetch:
user_chats.append(cur_chat)
self.delegate.didUpdateChats(user_chats)
In your collectionView controller:
class viewController: ChatsDelegate, ... {
...
func didUpdateChats(chatsArray: NSArray) {
dispatch_async(dispatch_get_main_queue()) {
self.collectionView.reloadData()
}
}
I put three table view controllers on pageviewcontroller.
The pageviewcontroller loads middle vc.
When I go to the left vc, and pull table in order to reload - I have problem that on function cellForRowAtIndexPath the indexPath.row starts from 4, not 0.
Why does the indexPath.row start from 4 and not 0?
I think, it is not about code issue! I have error:
Cannot index empty buffer
I ve found the error. I dont know why does this happens but when I reload table (pulling it), for some reason, it takes the last row (in my case I have 4 rows on screen counting from 0) and uses it in cellAtIndex array. Every time before pulling data from internet I remove all elements from array. I changed that code, i did remove all elements before reloading and the error didnt appear. What's interesting I am using the same function on other vc and everything works.
I am making two request to download data:
class func JSONRequest2(urlInput: String, tableName: UITableView, action: (NSArray)->Void, refresh:UIRefreshControl, viewContr: UIViewController, hideLoadingViewAndStopAnimating: ()->Void) {
let urlPath = urlInput
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
println("started first json request")
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if error != nil {
println(error)
let stringError = error.localizedDescription
CommonFunctions.showAlert("Ошибка", alertText: stringError, alertButtonText: "Закрыть", viewController: viewContr)
}
else{
var err: NSError?
if data != nil {
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSArray {
println("the number of news in json :\(jsonResult.count)")
if (err == nil) {
dispatch_async(dispatch_get_main_queue(), {
action(jsonResult)
//tableName.reloadData()
})
}else{
let stringError = err?.localizedDescription
CommonFunctions.showAlert("Ошибка", alertText: stringError!, alertButtonText: "Закрыть", viewController: viewContr)
}
}else {
hideLoadingViewAndStopAnimating()
println("json is not valid")
var dic = dictForErrors()
CommonFunctions.showAlert("Ошибка", alertText: dic.alertText, alertButtonText: "Закрыть", viewController: viewContr)
}
}else {
CommonFunctions.showAlert("Ошибка", alertText: "data is nil",alertButtonText: "Закрыть", viewController: viewContr)
println("json data is nil")
}
}
})
task.resume()
}
class func JSONRequest(urlInput: String, tableName: UITableView, action: (NSArray)->Void, refresh:UIRefreshControl, category: Int, viewContr: UIViewController, hideLoadingViewAndStopAnimating: ()->Void) {
//refresh.beginRefreshing()
let urlPath = urlInput
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
println("started second request")
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if error != nil {
println(error)
let stringError = error.localizedDescription
CommonFunctions.showAlert("Ошибка", alertText: stringError, alertButtonText: "Закрыть", viewController: viewContr)
}
else{
var err: NSError?
if data != nil{
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSArray {
println("the number of news in json :\(jsonResult.count)")
if (err == nil) {
dispatch_async(dispatch_get_main_queue(), {
action(jsonResult)
hideLoadingViewAndStopAnimating()
tableName.reloadData()
refresh.endRefreshing()
})
}else{
let stringError = err?.localizedDescription
hideLoadingViewAndStopAnimating()
CommonFunctions.showAlert("Ошибка", alertText: stringError!, alertButtonText: "Закрыть", viewController: viewContr)
}
}else {
hideLoadingViewAndStopAnimating()
println("json is not valid")
var dic = dictForErrors()
CommonFunctions.showAlert("Ошибка", alertText: dic.alertText, alertButtonText: "Закрыть", viewController: viewContr)
}
}else{
CommonFunctions.showAlert("Ошибка", alertText: "data is nil",alertButtonText: "Закрыть", viewController: viewContr)
println("json data is nil")
}
}
})
task.resume()
}
This is how I am making request in order to download two request
self.refreshControl = self.refreshController
self.refreshControl?.addTarget(self, action: "loadDataNewsLenta", forControlEvents: .ValueChanged)
if arrayMainPage.count > 0 {
activityView.alpha = 0.0
arrayNewSLenta = arrayMainPage
self.tableView.reloadData()
}else{
// loading first time news
activityView.alpha = 0.5
activityIndicator.startAnimating()
isFirstReq = true
arrayNewSLenta.removeAll(keepCapacity: false)
CommonFunctions.JSONRequest2(urlString, tableName: tableView, action: desirializeJSONToArray, refresh: self.refreshController, viewContr: self, hidLoadingViewAndStopAnimating)
}
I put the code above on viewdidload. This code is where I am reloading :
func hidLoadingViewAndStopAnimating() {
activityView.alpha = 0
activityIndicator.stopAnimating()
}
func configureTableView() {
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 110.0
}
func loadDataNewsLenta() {
arrayNewSLenta.removeAll(keepCapacity: false)
isFirstReq = true
refreshController.beginRefreshing()
CommonFunctions.JSONRequest2(urlString, tableName: tableView, action: desirializeJSONToArray, refresh: self.refreshController, viewContr: self, hidLoadingViewAndStopAnimating)
}
This is all about tableview code and desirialization of json to array:
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println("it is news lenta count \(arrayNewSLenta.count)")
return arrayNewSLenta.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("lentaCell", forIndexPath: indexPath) as LentaTableViewCell
let inex = indexPath.row
cell.labelDateOfPublication.text = arrayNewSLenta[indexPath.row].pubDate
cell.labeltitle.text = arrayNewSLenta[indexPath.row].pageTitle
return cell
}
func desirializeJSONToArray(jsonArray: NSArray){
for singleJSON in jsonArray{
var singleArticle = ArticleInfo()
if let arrayText = singleJSON as? NSDictionary{
if let articleID = arrayText["id"] as? NSString{
singleArticle.articleID = articleID
}
if let pageTitle = arrayText["pagetitle"] as? NSString {
singleArticle.pageTitle = pageTitle
}
if let longTitle = arrayText["longtitle"] as? String{
singleArticle.longTitle = longTitle
}
if let introText = arrayText["introtext"] as? String{
singleArticle.introText = introText
}
if let contentText = arrayText["content_text"] as? String{
singleArticle.contentText = contentText
}
if let category = arrayText["category"] as? String{
singleArticle.category = category
}
if let imageLink = arrayText["thumbnail"] as? String{
singleArticle.linkToImage = imageLink
}
if let videoLink = arrayText["video"] as? String{
singleArticle.videoLink = videoLink
println("hre is video link")
println(videoLink)
}
if let sity = arrayText["sity"] as? String{
singleArticle.sity = sity
}
if let visible = arrayText["visible"] as? String{
singleArticle.visible = visible
}
if let visits = arrayText["visits"] as? String{
singleArticle.visits = visits
}
if let pubDate = arrayText["pubdate"] as? String{
singleArticle.pubDate = pubDate
}
// insert result into array
arrayNewSLenta.append(singleArticle)
}
}
//cycle ended
if isFirstReq == true {
let urlStringSecondRequest = "http://www.kfdz/artifdcles/JsonMainList"
CommonFunctions.JSONRequest(urlStringSecondRequest, tableName: tableView, action: desirializeJSONToArray, refresh: self.refreshController, category: 0, viewContr: self, hidLoadingViewAndStopAnimating)
}
isFirstReq = false
}
The interesting fact I noticed , when I go to first vc and pull table immediately, for some reason it load cellAtIndex function using only the last row on screen(in my case index 4). on the other hand, when I go to first vc and choose some item (to see detailed view) and go back and pull table everything works.
On more issue to say, when I change transition style of uipageviewcontroller to PageCurl I dont have this problem!
You can instead of using 3 table view in a single view, you should use the container view in the first view and put all the view tables in different views as shown in the picture below :
You need 1 file for each table view created.
the bug can probably disappear like that