Reputation: 323
I have a chat feature on my app that updates the table instantly when a user enters new text. Unfortunately when a user enters the text it shows any empty row in the uitableview. When I exit out of the screen and return that new value is now there at the end of the table. So even though it's showing an empty row in the uitableview it's submitting the actual value to the database.
class ConversationViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
//var user = NSDictionary()
var messages = NSDictionary()
var hhmessages = [AnyObject]()
//var messages: [Message] = []
var pictures = [UIImage]()
var avas = [UIImage]()
var avaURL = [String]()
var isLoading = false
var skip = 0
var limit = 50
var images = [UIImage]()
var incoming: [Int] = []
var comments = [String]()
var ids = [String]()
@IBOutlet var replyTxt: UITextView!
@IBOutlet var replyTxt_height: NSLayoutConstraint!
@IBOutlet var replyTxt_bottom: NSLayoutConstraint!
@IBOutlet var replyBtn: UIButton!
var commentsTextView_bottom_identity = CGFloat()
@IBOutlet var tableView: UITableView!
// Table View here + basic configuration
override func viewDidLoad() {
super.viewDidLoad()
// dynamic cell height
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
loadPosts()
replyTxt.layer.cornerRadius = replyTxt.bounds.width / 50
replyTxt.backgroundColor = UIColor.clear
replyTxt.layer.borderColor = UIColor.gray.cgColor
replyTxt.layer.borderWidth = 1.0
let username = messages["sender"] as? String
self.navigationItem.title = username
}
// TABLEVIEW
// Number os cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hhmessages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let colorSmoothGray = UIColor(red: 229/255, green: 229/255, blue: 234/255, alpha: 1)
let colorBrandBlue = UIColor(red: 148 / 255, green: 33 / 255, blue: 147 / 255, alpha: 1)
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
// no picture in the post
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
// shortcuts
let hhpost = hhmessages[indexPath.row]
let text = hhpost["messagetext"] as? String
cell.messageLbl.text = text
return cell
}
// func of loading posts from server
@objc func loadPosts() {
//isLoading = true
let me = user!["username"] as! String
let meid = user!["id"] as! String
print(meid)
print(me)
//print(username)
let uuid = messages["uuid"] as! String
print(uuid)
// accessing php file via url path
let url = URL(string: "http://localhost/message.php")!
// pass information to php file
let body = "username=\(me)&uuid=\(uuid)&recipient_id=\(meid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: String.Encoding.utf8)
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
// launch session
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// no error of accessing php file
// error occured
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
//self.isLoading = false
return
}
do {
// access data - safe mode
guard let data = data else {
Helper().showAlert(title: "Data Error", message: error!.localizedDescription, in: self)
//self.isLoading = false
return
}
// getting content of $returnArray variable of php file
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
// accessing json data - safe mode
guard let posts = json?["messages"] as? [NSDictionary] else {
//self.isLoading = false
return
}
// assigning all successfully loaded posts to our Class Var - posts (after it got loaded successfully)
self.hhmessages = posts
self.tableView.reloadData()
// scroll to the latest index (latest cell -> bottom)
let indexPath = IndexPath(row: self.hhmessages.count - 1, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
// self.isLoading = false
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
//self.isLoading = false
return
}
}
}.resume()
}
// function sending requset to PHP to uplaod a file
func uploadPost() {
// validating vars before sending to the server
guard let user_id = user?["id"] as? String, let username = user?["username"] as? String, let avaPath = user?["ava"] else {
// converting url string to the valid URL
if let url = URL(string: user?["ava"] as! String) {
// downloading all data from the URL
guard let data = try? Data(contentsOf: url) else {
return
}
// converting donwloaded data to the image
guard let image = UIImage(data: data) else {
return
}
// assigning image to the global var
let currentUser_ava = image
}
return
}
let user_id_int = Int(user_id)!
let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
let indexPath = IndexPath(row: hhmessages.count - 1, section: 0)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
tableView.transform = CGAffineTransform(rotationAngle: -(CGFloat)(Double.pi));
tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
replyTxt.text = ""
textViewDidChange(replyTxt)
let recipient = messages["username"] as! String
let rid = String(describing: messages["recipient_id"]!)
let uuid = messages["uuid"] as! String
puuid = UUID().uuidString
// prepare request
let url = URL(string: "http://localhost/messagepost.php")!
let body = "sender_id=\(user_id)&sender=\(username)&text=\(messagetext)&recipient_id=\(rid)&recipient=\(recipient)&uuid=\(uuid)&puuid=\(puuid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: .utf8)
// send request
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// error happened
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
return
}
do {
// converting received data from the server into json format
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
// safe mode of casting json
guard let parsedJSON = json else {
return
}
// if the status of JSON is 200 - success
if parsedJSON["status"] as! String == "200" {
} else {
Helper().showAlert(title: "400", message: parsedJSON["status"] as! String, in: self)
return
}
// json error
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
return
}
}
}.resume()
}
@IBAction func replyBtn_clicked(_ sender: Any) {
if replyTxt.text.isEmpty == false && replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false {
uploadPost()
//tableView.reloadData()
}
}
Upvotes: 0
Views: 48
Reputation: 15758
While appending a new message you are adding a String
to the hhmessages
array
let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
But in cellForRowAt
method you are trying to get the String
from hhmessages
array using "messagetext" key
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
let hhpost = hhmessages[indexPath.row]
let text = hhpost["messagetext"] as? String
Change
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
to
hhmessages.insert(["messagetext": messagetext] as AnyObject, at: hhmessages.endIndex)
Instead of using array of AnyObject, use a struct
var hhmessages = AnyObject
struct Message {
var uploadpath: URL?
var messagetext: String?
}
var hhmessages = [Message]()
Upvotes: 1