I want to updated tableview from web services on change of segmented Control. As my code i have triggered event segmentedControlAction to update tableview in viewDidAppear event. it works on first time on Screen load but not working when i select next tab(Following), it fetch data from web service not update tableview. but when i switch to first Followers tab then come again to following tab it works, because it store data fetched from previuos web service
Datasource(ds) is get data from web service incase if it has nil records
TsButton is custom class which has only one member variable is object which is used for passing extra information to button click event
In StoryBoard there are two controls Segmented Control and tableview like in screen shot
My Code is below
class UserFollowController: BaseViewController
{
#IBOutlet var segmentedControl: UISegmentedControl!
#IBOutlet var tableView: UITableView!
private var ds : UserFollowTableDataSource!
override func viewDidLoad()
{
super.viewDidLoad()
ds = UserFollowTableDataSource(vc: self, tableView: tableView);
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if UserEntity.instance.username.characters.count == 0
{
let storyBoard : UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "LoginController") as! LoginController
self.tabBarController?.selectedIndex = 0
self.present(vc, animated: true, completion: nil)
}
else
{
self.segmentedControlAction(sender: nil);
}
}
#IBAction func segmentedControlAction(sender: AnyObject?) {
if(segmentedControl.selectedSegmentIndex == 0)
{
ds.fetchFromWeb(type: "follower")
}
else
{
ds.fetchFromWeb(type: "following")
}
}
}
class UserFollowTableDataSource : NSObject, UITableViewDataSource
{
private var follower_records : [[String : Any]]?;
private var following_records : [[String : Any]]?;
private var records : [[String : Any]]?;
private var tableView : UITableView!;
private var vc : UserFollowController!;
private var loader : UIAlertController!;
private var type : String!
init(vc : UserFollowController, tableView : UITableView)
{
self.vc = vc;
self.tableView = tableView
self.loader = CommonUtil.getLoader(msg: "Getting List...");
super.init()
self.tableView.dataSource = self;
}
public func fetchFromWeb(type : String)
{
self.type = type;
self.loader.title = "Getting List...";
if (type == "follower")
{
if let data = self.follower_records
{
self.records = data;
self.tableView.reloadData();
self.tableView.setNeedsDisplay();
return;
}
self.vc.present(self.loader, animated: true, completion: nil)
HauteWebService.instance.get_user_followers(onSucess: { (response) in
if (response.status == 1)
{
DispatchQueue.main.async {
self.loader.dismiss(animated: true, completion: {
self.follower_records = response.data as! [[String : Any]]
self.records = self.follower_records
self.tableView.reloadData();
});
}
}
else
{
self._onError(msg: response.msg);
}
}, onFailure: { (msg) in
self._onError(msg: msg);
})
}
else
{
if let data = self.following_records
{
self.records = data;
self.tableView.reloadData();
self.tableView.setNeedsDisplay();
return;
}
self.vc.present(self.loader, animated: true, completion: nil)
HauteWebService.instance.get_user_following(onSucess: { (response) in
if (response.status == 1)
{
DispatchQueue.main.async {
self.loader.dismiss(animated: true, completion: {
self.following_records = response.data as! [[String : Any]]
self.records = self.follower_records
self.tableView.reloadData();
})
}
}
else
{
self._onError(msg: response.msg);
}
}, onFailure: { (msg) in
self._onError(msg: msg);
})
}
}
private func _onError(msg : String)
{
DispatchQueue.main.async {
self.loader.dismiss(animated: true, completion: {
let alert = CommonUtil.getAlertError(title: "Error while getting web service", msg: msg);
self.vc?.present(alert, animated: true, completion: nil)
})
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.records != nil
{
return self.records!.count;
}
return 0;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "FollowTableCell", for: indexPath) as! FollowTableCell
let index = indexPath.row;
cell.tag = index;
if let record = self.records![index] as? [String : Any]
{
let first = record["firstname"] as! String
let last = record["lastname"] as! String
cell.lblName.text = first + " " + last;
var add = record["city"] as! String;
let state = record["state"] as! String;
if state != ""
{
add = add + ", " + state
}
cell.lblAddress.text = add;
cell.btnFollow.backgroundColor = TFColor.hexToUIColor(hex: "#AAAAAA")
cell.btnFollow.setTitle("Follow", for: .normal)
cell.btnFollow.object = record;
if let v = record["is_followed"] as? Int
{
if (v == 1)
{
cell.btnFollow.backgroundColor = TFColor.hexToUIColor(hex: "#887474")
cell.btnFollow.setTitle("Following", for: .normal)
}
}
cell.btnFollow.addTarget(self, action: #selector(self.btnFollowClick), for: .touchUpInside)
cell.ratingStar.changeEvent = false;
if let v = Float(record["rating"] as! String)
{
cell.ratingStar.rating = Int(v)
}
else
{
cell.ratingStar.rating = 0;
}
cell.imgProfile.image = UIImage(named: "no_image");
if let url = record["profile_image_url"] as? String
{
if let img = ImageEntity.readCache(key: url)
{
cell.imgProfile.image = img
}
else
{
HauteWebService.instance.downloadFile(url: url, onSucess: { (data) in
if let img = UIImage(data: data)
{
ImageEntity.writeCache(key: url, image: img)
DispatchQueue.main.async {
if cell.tag == index
{
cell.imgProfile.image = img
}
}
}
}, onFailure: { (msg) in
})
}
}
}
return cell;
}
#objc func btnFollowClick(_ sender: TsButton)
{
let record = sender.object as! [String : Any];
let id = record["id"] as! String;
let data = ["user_id" : id]
if let v = record["is_followed"] as? Int
{
self.loader.title = "Please Wait...";
vc.present(self.loader, animated: true, completion: nil);
if (v == 1)
{
HauteWebService.instance.delete_user_follow(data: data, onSucess: { (response) in
if (response.status == 1)
{
DispatchQueue.main.async {
self.loader.dismiss(animated: false, completion: {
DispatchQueue.main.async {
self.follower_records = nil
self.following_records = nil
self.fetchFromWeb(type : self.type)
}
});
}
}
else
{
self._onError(msg: response.msg)
}
}, onFailure: { (msg) in
self._onError(msg: msg);
})
}
else
{
HauteWebService.instance.save_user_follow(data: data, onSucess: { (response) in
if (response.status == 1)
{
DispatchQueue.main.async {
self.loader.dismiss(animated: false, completion: {
DispatchQueue.main.async {
self.follower_records = nil
self.following_records = nil
self.fetchFromWeb(type : self.type)
}
});
}
}
else
{
self._onError(msg: response.msg)
}
}, onFailure: { (msg) in
self._onError(msg: msg);
})
}
}
}
}
class FollowTableCell : UITableViewCell
{
#IBOutlet var imgProfile : UIImageView!
#IBOutlet var actvityImgProfile : UIActivityIndicatorView!
#IBOutlet var lblName : UILabel!
#IBOutlet var lblAddress : UILabel!
#IBOutlet var btnFollow : TsButton!
#IBOutlet var ratingStar : TsRatingStar!
}
In your following webservice callback you have
self.following_records = response.data as! [[String : Any]]
self.records = self.follower_records
Thus you are setting the records of the tableView to the wrong values in the webservice callback.
It should be:
self.following_records = response.data as! [[String : Any]]
self.records = self.following_records
Related
I have a problem with passing the data
To make it clear, I will explain the idea of what I worked on, and what is the problem.
The idea is in the first view controller the user will enter the title and description and then chooses from the options of the pop-up button, the options are (exchange, borrow, donation, sell). The data entered will be saved in the option chosen by the user. then the data will be displayed in the second view controller in the table view. If the user chooses the exchange option and enters the data, his data will be displayed in the table view in the exchange (index 0) and this works for me the data is displayed in the table view in the correct form as I want.
The problem I am experiencing is when I pass the data to the other view controller.
When the user clicks on any cell, it will pass the same data regardless of the difference in the index. If the user chooses the borrow (index 1) and clicks any cell, it'll display the exchange (index 0) data. No matter what indexes you choose and the cell you click on it will pass the same data!!!!!
first view controller
here I'm entering the data
it's shown in the table view in the right index of the segment no problem with that
after I click it pass the right data
look here if I change the index and click to any cell it will pass the same data!!
look here if I change the index and click to any cell it will pass the same data!!
Here's my code for the first vc
import UIKit
import FirebaseFirestore
class ViewController4: UIViewController {
#IBOutlet weak var mssglabel: UILabel!
#IBOutlet weak var selectservice: UIButton!
#IBOutlet weak var titleTextField: UITextField!
#IBOutlet weak var descriptionTextField: UITextView!
#IBOutlet weak var custombtun: UIButton!
let db = Firestore.firestore()
var chooseOption = ""
override func viewDidLoad() {
super.viewDidLoad()
setpopupbutn()
selectservice.layer.cornerRadius = 25
descriptionTextField.layer.cornerRadius = 25
custombtun.layer.cornerRadius = 25
}
#IBAction func containbutn(_ sender: Any) {
let vc = (storyboard?.instantiateViewController(withIdentifier: "vc3"))!
navigationController?.pushViewController(vc, animated: true)
spcificOption()
}
func saveDataDonation() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text{
// Save Data to Database
db.collection("userDonationDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle)
}
} // end of closure
}
}
func saveDataSale() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text{
// Save Data to Database
db.collection("userSaleDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func saveDataExchange() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text {
// Save Data to Database
db.collection("userExchangeDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func saveDataBorrow() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text {
// Save Data to Database
db.collection("userBorrowDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func setpopupbutn () {
let option = {( ACTION : UIAction ) in
self.chooseOption = ACTION.title
print("حفظ الداتا في ",self.chooseOption)}
selectservice.menu = UIMenu (children : [
UIAction (title : "تبرع" , state: .on , handler: option),
UIAction (title : "بيع" , handler: option),
UIAction (title : "تبادل" , handler: option),
UIAction (title : "إستعارة" , handler: option),
])
saveDataDonation()
selectservice.showsMenuAsPrimaryAction = true
selectservice.changesSelectionAsPrimaryAction = true
}
func spcificOption() {
if chooseOption == ("تبرع") {
saveDataDonation()
} else if chooseOption == ("بيع") {
saveDataSale()
} else if chooseOption == ("تبادل") {
saveDataExchange()
} else if chooseOption == ("إستعارة") {
saveDataBorrow()
}
}
}
and this is the second vc (Table view)
import UIKit
import FirebaseFirestore
import Firebase
class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {
let db = Firestore.firestore()
var exchange : [exchange] = []
var borrow : [borrow] = []
var donation : [donation] = []
var sale : [sale] = []
#IBOutlet weak var segmentOutlet: UISegmentedControl!
#IBOutlet weak var userDataTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
userDataTableView.dataSource = self
userDataTableView.delegate = self
getDataDonation()
getDataSale()
getDataExchange()
getDataBorrow()
userDataTableView.reloadData()
}
#IBAction func serviceSeg(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
getDataExchange()
}
else if sender.selectedSegmentIndex == 1 {
getDataBorrow()
}
else if sender.selectedSegmentIndex == 2 {
getDataDonation()
}
else if sender.selectedSegmentIndex == 3 {
getDataSale()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentOutlet.selectedSegmentIndex == 0 {
return exchange.count
} else if segmentOutlet.selectedSegmentIndex == 1 {
return borrow.count
}else if segmentOutlet.selectedSegmentIndex == 2 {
return donation.count
} else if segmentOutlet.selectedSegmentIndex == 3 {
return sale.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if segmentOutlet.selectedSegmentIndex == 0 {
cell.textLabel?.text = exchange [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 1 {
cell.textLabel?.text = borrow [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 2 {
cell.textLabel?.text = donation [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 3 {
cell.textLabel?.text = sale [indexPath.row].passTitle
}
return cell
}
func getDataDonation(){
donation.removeAll()
db.collection("userDonationDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.donation.append(finalProject.donation(passTitle3:data["BookTitle"] as! String , passDes3: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataSale(){
sale.removeAll()
db.collection("userSaleDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.sale.append(finalProject.sale(passTitle4:data["BookTitle"] as! String , passDes4: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataExchange(){
exchange.removeAll()
db.collection("userExchangeDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.exchange.append(finalProject.exchange(passTitle1:data["BookTitle"] as! String , passDes1: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataBorrow(){
borrow.removeAll()
db.collection("userBorrowDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.borrow.append(finalProject.borrow(passTitle2:data["BookTitle"] as! String , passDes2: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
Note... I tried to do this but it didn't work
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
vc.recivedB = borrow[indexPath.row]
vc.recivedD = donation[indexPath.row]
vc.recivedS = sale[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
This is the struct,
I created a struct for each index
public struct exchange {
var passTitle : String
var passDes : String
init (passTitle1:String, passDes1:String) {
self.passTitle = passTitle1
self.passDes = passDes1
}
}
public struct borrow {
var passTitle : String
var passDes : String
init (passTitle2:String, passDes2:String) {
self.passTitle = passTitle2
self.passDes = passDes2
}
}
public struct donation {
var passTitle : String
var passDes : String
init (passTitle3:String, passDes3:String) {
self.passTitle = passTitle3
self.passDes = passDes3
}
}
public struct sale {
var passTitle : String
var passDes : String
init (passTitle4:String, passDes4:String) {
self.passTitle = passTitle4
self.passDes = passDes4
}
}
this is the last vc
import UIKit
import FirebaseStorage
import Firebase
import FirebaseFirestore
import SDWebImage
class ViewController10: UIViewController {
#IBOutlet weak var userBookTitle: UILabel!
#IBOutlet weak var userBookDescription: UILabel!
var recivedE:exchange?
var recivedB:borrow?
var recivedD:donation?
var recivedS:sale?
override func viewDidLoad() {
super.viewDidLoad()
userBookTitle.text = recivedE?.passTitle
userBookDescription.text = recivedE?.passDes
}
}
Note... I tried to do this but it didn't work
override func viewDidLoad() {
super.viewDidLoad()
if let et = recivedE?.passTitle ,
let ed = recivedE?.passDes{
userBookTitle.text = et
userBookDescription.text = ed
}
else if let bt = recivedB?.passTitle ,
let bd = recivedB?.passDes {
userBookTitle.text = bt
userBookDescription.text = bd
}
else if let dt = recivedD?.passTitle ,
let dd = recivedD?.passDes {
userBookTitle.text = dt
userBookDescription.text = dd
}
else if let st = recivedS?.passTitle ,
let sd = recivedS?.passDes {
userBookTitle.text = st
userBookDescription.text = sd
}
}
and this also not working
override func viewDidLoad() {
super.viewDidLoad()
userBookTitle.text = recivedE?.passTitle
userBookDescription.text = recivedE?.passDes
userBookTitle.text = recivedB?.passTitle
userBookDescription.text = recivedB?.passDes
userBookTitle.text = recivedD?.passTitle
userBookDescription.text = recivedD?.passDes
userBookTitle.text = recivedS?.passTitle
userBookDescription.text = recivedS?.passDes
}
help me, please
In both of your numberOfRowsInSection and cellForRowAt functions, you are checking the selected segment index to determine which data to use:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentOutlet.selectedSegmentIndex == 0 {
return exchange.count
} else if segmentOutlet.selectedSegmentIndex == 1 {
return borrow.count
}else if segmentOutlet.selectedSegmentIndex == 2 {
return donation.count
} else if segmentOutlet.selectedSegmentIndex == 3 {
return sale.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if segmentOutlet.selectedSegmentIndex == 0 {
cell.textLabel?.text = exchange [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 1 {
cell.textLabel?.text = borrow [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 2 {
cell.textLabel?.text = donation [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 3 {
cell.textLabel?.text = sale [indexPath.row].passTitle
}
return cell
}
However, in didSelectRowAt, you only use the exchange data:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
If you implement the same if / else if structure in didSelectRowAt you should get the desired results.
I have been using 'MessengerKit' for my chat section of my app. I can write and ready messages from firebase but when the chat updates, the messages duplicates sequentially(once, twice, thrice and so on). I am attaching my chatViewController Code below along with the message view on the app.
chatViewController Code :
class chatViewController: MSGMessengerViewController {
// Users in the chat
var nameOfHirer : String = ""
var nameofSeeker : String = ""
var seekerData = User(displayName: "", avatar: nil, isSender: false)
var hirerData = User(displayName: "", avatar: nil, isSender: true)
var id = 100
// Messages
lazy var messages: [[MSGMessage]] = []
func retrieveSeeker() {
let db = Firestore.firestore()
db.collection("Posts").document(jobID).collection("Applications").whereField("ID", isEqualTo: userID).getDocuments { (document, error) in
for document in document!.documents {
if error != nil {
}else {
let Name = document.get("Name") as! String
self.nameofSeeker = Name
let seeker = User(displayName: Name, avatar: nil, isSender: false)
self.seekerData = seeker
}
}
}
}
func retrieveHirer() {
let db = Firestore.firestore()
db.collection("Posts").document(jobID).getDocument { (document, error) in
if error != nil {
}else {
let Hirer = document?.get("Company Name") as! String
self.nameOfHirer = Hirer
let hirer = User(displayName: Hirer, avatar: nil, isSender: true)
self.hirerData = hirer
}
}
}
var uniqueID : String = ""
var messageBody : String = ""
var jobID : String = ""
var userID : String = ""
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
retrieveHirer()
retrieveSeeker()
// retrieveMessages()
print(messageBody)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = true
}
override var style: MSGMessengerStyle {
var style = MessengerKit.Styles.travamigos
style.inputPlaceholder = "Type your message here"
return style
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
collectionView.scrollToBottom(animated: false)
}
override func inputViewPrimaryActionTriggered(inputView: MSGInputView) {
id += 1
var newMessage : String = ""
let messageDictionary = ["Sender": userID, "MessageBody": inputView.message, "JobID": jobID]
// let body = MSGMessageBody.text(newMessage)
//
// let message = MSGMessage(id: id, body: body, user: hirerData, sentAt: Date())
inputView.resignFirstResponder()
let messageDB = Database.database().reference().child("Messages").child(jobID).child(userID)
messageDB.childByAutoId().setValue(messageDictionary) { (error, reference) in
if error != nil {
}else {
retrievemess()
}
}
func retrievemess() {
let messageDB = Database.database().reference().child("Messages").child(jobID).child(userID).queryLimited(toLast: 1)
messageDB.observe(.childAdded) { (snapshot) in
let value = snapshot.value as? [String: AnyObject]
let allmessage = value!["MessageBody"]
let body = MSGMessageBody.text(allmessage as! String)
let newmessage = MSGMessage(id: self.id, body: body, user: self.hirerData, sentAt: Date())
self.insert(newmessage)
}
}
}
override func insert(_ message: MSGMessage) {
collectionView.performBatchUpdates({
if let lastSection = self.messages.last, let lastMessage = lastSection.last, lastMessage.user.displayName == message.user.displayName {
self.messages[self.messages.count - 1].append(message)
let sectionIndex = self.messages.count - 1
let itemIndex = self.messages[sectionIndex].count - 1
self.collectionView.insertItems(at: [IndexPath(item: itemIndex, section: sectionIndex)])
} else {
print(messages.count)
self.messages.append([message])
let sectionIndex = self.messages.count - 1
self.collectionView.insertSections([sectionIndex])
}
}, completion: { (_) in
self.collectionView.scrollToBottom(animated: true)
self.collectionView.layoutTypingLabelIfNeeded()
})
}
override func insert(_ messages: [MSGMessage], callback: (() -> Void)? = nil) {
collectionView.performBatchUpdates({
for message in messages {
if let lastSection = self.messages.last, let lastMessage = lastSection.last, lastMessage.user.displayName == message.user.displayName {
self.messages[self.messages.count - 1].append(message)
let sectionIndex = self.messages.count - 1
let itemIndex = self.messages[sectionIndex].count - 1
self.collectionView.insertItems(at: [IndexPath(item: itemIndex, section: sectionIndex)])
} else {
self.messages.append([message])
let sectionIndex = self.messages.count - 1
self.collectionView.insertSections([sectionIndex])
}
}
}, completion: { (_) in
self.collectionView.scrollToBottom(animated: false)
self.collectionView.layoutTypingLabelIfNeeded()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
callback?()
}
})
}
}
// MARK: - MSGDataSource
extension chatViewController: MSGDataSource {
func numberOfSections() -> Int {
return messages.count
}
func numberOfMessages(in section: Int) -> Int {
return messages[section].count
}
func message(for indexPath: IndexPath) -> MSGMessage {
return messages[indexPath.section][indexPath.item]
}
func footerTitle(for section: Int) -> String? {
return "Just now"
}
func headerTitle(for section: Int) -> String? {
return messages[section].first?.user.displayName
}
}
// MARK: - MSGDelegate
extension chatViewController: MSGDelegate {
func linkTapped(url: URL) {
print("Link tapped:", url)
}
func avatarTapped(for user: MSGUser) {
print("Avatar tapped:", user)
}
func tapReceived(for message: MSGMessage) {
print("Tapped: ", message)
}
func longPressReceieved(for message: MSGMessage) {
print("Long press:", message)
}
func shouldDisplaySafari(for url: URL) -> Bool {
return true
}
func shouldOpen(url: URL) -> Bool {
return true
}
}
The pod I'm using is - https://github.com/steve228uk/MessengerKit
Screenshot:
Ok So I got the issue. The problem is that with
.queryLimited(toLast: 1).observe(.childAdded)
gives back multiple entries after first the first time its fired. The solution was to change .observe to .observeSingleEvent
I have an issue where I click on a tableviewcell and it is supposed to populate a detail view controller but when I click the cell this error pops up.
import UIKit
import Former
import Parse
import MapKit
import Material
import CoreLocation
class EventDetailViewController: FormViewController, MKMapViewDelegate, CLLocationManagerDelegate {
// MARK: Public
var event: PFObject?
var organizer: PFUser?
var currentUserStatus = 2
var confirmedUsers = [PFObject]()
var maybeUsers = [PFObject]()
var invitedUsers = [PFObject]()
var confirmedUserIDs = [String]()
var maybeUserIDs = [String]()
var invitedUserIDSs = [String]()
// MARK: Public
override func viewDidLoad() {
super.viewDidLoad()
// Configure UI
title = "Event Details"
tableView.contentInset.top = 0
tableView.contentInset.bottom = 30
navigationItem.leftBarButtonItem = UIBarButtonItem(image: Icon.cm.close, style: .plain, target: self, action: #selector(cancelButtonPressed))
organizer = event?.object(forKey: PF_EVENTS_ORGANIZER) as? PFUser
organizer!.fetchInBackground { (user: PFObject?, error: Error?) in
if error == nil {
self.insertEventDetail()
for pointer in (self.event?.object(forKey: PF_EVENTS_CONFIRMED) as! [PFUser]) {
pointer.fetchInBackground(block: { (user: PFObject?, error: Error?) in
if error == nil {
if user?.objectId == PFUser.current()?.objectId {
self.currentUserStatus = 0
self.choiceRow.configure(handler: {
$0.selectedIndex = self.currentUserStatus
})
}
self.confirmedUsers.append(user!)
self.confirmedUserIDs.append(user!.objectId!)
if pointer == (self.event?.object(forKey: PF_EVENTS_CONFIRMED) as! [PFUser]).last {
// All users have been downloaded
self.insertUsers(users: self.confirmedUsers, header: "Going", section: 2)
if self.currentUserStatus == 0 {
self.former.insertUpdate(rowFormer: self.newRow, toIndexPath: IndexPath(row: 0, section: 2), rowAnimation: .fade)
}
}
}
})
}
for pointer in (self.event?.object(forKey: PF_EVENTS_MAYBE) as! [PFUser]) {
pointer.fetchInBackground(block: { (user: PFObject?, error: Error?) in
if error == nil {
if user?.objectId == PFUser.current()?.objectId {
self.currentUserStatus = 1
self.choiceRow.configure(handler: {
$0.selectedIndex = self.currentUserStatus
})
}
self.maybeUsers.append(user!)
self.maybeUserIDs.append(user!.objectId!)
if pointer == (self.event?.object(forKey: PF_EVENTS_MAYBE) as! [PFUser]).last {
// All users have been downloaded
var section = 3
if self.former.sectionFormers.count < 2 {
section = 2
}
self.insertUsers(users: self.maybeUsers, header: "Maybe", section: section)
if self.currentUserStatus == 1 {
self.former.insertUpdate(rowFormer: self.newRow, toIndexPath: IndexPath(row: 0, section: section), rowAnimation: .fade)
}
}
}
})
}
for pointer in (self.event?.object(forKey: PF_EVENTS_INVITE_TO) as! [PFUser]) {
pointer.fetchInBackground(block: { (user: PFObject?, error: Error?) in
if error == nil {
self.invitedUsers.append(user!)
if pointer == (self.event?.object(forKey: PF_EVENTS_INVITE_TO) as! [PFUser]).last {
// All users have been downloaded
var section = 4
if self.former.sectionFormers.count == 2 {
section = 3
} else if self.former.sectionFormers.count < 2 {
section = 2
}
self.insertUsers(users: self.invitedUsers, header: "Invited", section: section)
}
}
})
}
if (self.event?.object(forKey: PF_EVENTS_CONFIRMED) as! [PFUser]).count == 0 {
self.insertEmpty(header: "Confirmed")
}
if (self.event?.object(forKey: PF_EVENTS_MAYBE) as! [PFUser]).count == 0 {
self.insertEmpty(header: "Maybe")
}
if (self.event?.object(forKey: PF_EVENTS_INVITE_TO) as! [PFUser]).count == 0 {
self.insertEmpty(header: "Invited")
}
}
}
if organizer?.objectId == PFUser.current()?.objectId {
navigationItem.rightBarButtonItem = UIBarButtonItem(image: Icon.cm.edit, style: .plain, target: self, action: #selector(editButtonPressed))
}
}
// MARK: Private
private func insertUsers(users: [PFObject], header: String, section: Int) {
var userRows = [LabelRowFormer<ProfileImageCell>]()
for user in users {
if user.objectId != PFUser.current()?.objectId {
userRows.append(LabelRowFormer<ProfileImageCell>(instantiateType: .Nib(nibName: "ProfileImageCell")) {
$0.iconView.backgroundColor = MAIN_COLOR
$0.iconView.layer.borderWidth = 1
$0.iconView.layer.borderColor = MAIN_COLOR?.cgColor
$0.iconView.image = UIImage(named: "profile_blank")
$0.iconView.file = user[PF_USER_PICTURE] as? PFFile
$0.iconView.loadInBackground()
$0.titleLabel.textColor = UIColor.black
}.configure {
$0.text = user[PF_USER_FULLNAME] as? String
$0.rowHeight = 60
}.onSelected { [weak self] _ in
self?.former.deselect(animated: true)
let profileVC = PublicProfileViewController()
profileVC.user = user
self?.navigationController?.pushViewController(profileVC, animated: true)
})
}
}
self.former.insert(sectionFormer: (sectionFormer: SectionFormer(rowFormers: userRows).set(headerViewFormer: TableFunctions.createHeader(text: header))) as! SectionFormer, toSection: section)
self.former.reload()
}
private func insertEmpty(header: String) {
let zeroRow = LabelRowFormer<ImageCell>(instantiateType: .Nib(nibName: "ImageCell")) { _ in
}.configure {
$0.rowHeight = 0
}
Below is where that Code gives me an EXC Bad Instruction
self.former.append(sectionFormer: (sectionFormer: SectionFormer(rowFormer: zeroRow).set(headerViewFormer: TableFunctions.createHeader(text: header))) as! SectionFormer)
self.former.reload()
}
I am rebuilding Instagram and want to show all User who liked a post.
I am Running into a problem that my tableview doesn't show the users who liked the post.
For a like I will add it on firebase
self.REF_LIKES_POSTS.child(postId).child(uid).setValue(true)
Now I want to get all the users who liked the post in my UsersLikedViewController
func loadUserLikes() {
API.User.REF_POST_USERS_LIKED.observe(.childAdded, with: {
snapshot in
API.User.observeUserLikes(withPostId: snapshot.key, completion: {
user in
self.fetchUser(uid: user.id!, completed: {
self.users.insert(user, at: 0)
self.tableView.reloadData()
})
})
})
}
func fetchUser(uid: String, completed: #escaping () -> Void) {
API.User.observeUser(withId: uid, completion: {
user in
self.users.insert(user, at: 0)
completed()
})
}
My User API
class UserApi {
var REF_USERS = FIRDatabase.database().reference().child("users")
var REF_POST_USERS_LIKED = FIRDatabase.database().reference().child("LikesFromUsers")
var REF_POST = FIRDatabase.database().reference().child("posts")
func observeUser(withId uid: String, completion: #escaping (User) -> Void) {
REF_USERS.child(uid).observeSingleEvent(of: .value, with: {
snapshot in
if let dict = snapshot.value as? [String: Any] {
let user = User.transformUserInfo(dict: dict, key: snapshot.key)
completion(user)
}
})
}
func observeUsers(completion: #escaping (User) -> Void) {
REF_USERS.observe(.childAdded, with: {
snapshot in
if let dict = snapshot.value as? [String: Any] {
let user = User.transformUserInfo(dict: dict, key: snapshot.key)
if user.id! != API.User.CURRENT_USER?.uid {
completion(user)
}
}
})
}
func observeUserLikes(withPostId id: String , completion: #escaping (User) -> Void) {
REF_POST_USERS_LIKED.child(id).observeSingleEvent(of: .value, with: {
snapshot in
if let dict = snapshot.value as? [String: Any]{
let allUsers = User.transformUserInfo(dict: dict, key: snapshot.key)
completion(allUsers)
}
})
}
}
My function fetchUser() in LoadUserLikes returns nil, so there is something missing.
I only accomplished that there were all the already shared posts, so a user could follow and unfollow a post but that makes no sense haha.
thanks for your time
"LikesFromUsers" : {
"-KjY30xwWA2IJBwlvyzf" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
}
},
"comments" : {
"-KjTIBDeMsho70t-jnGw" : {
"commentText" : "klasse Auto",
"creationDate" : 1.494083221667957E9,
"likeCount" : 0,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-Kjc-uvCSn7qz8VkDVCR" : {
"commentText" : "toll",
"creationDate" : 1.494246203366448E9,
"likeCount" : 0,
"uid" : "es5fIbnKFpX4szcCbroUqHjJg6E3"
},
"-Kjc01pbWUtZn8XMlRGL" : {
"commentText" : "fantatsico ",
"creationDate" : 1.494246235776034E9,
"likeCount" : 1,
"likes" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : true
},
}
},
"posts" : {
"-KjTBFFE5QzktG1IT5u0" : {
"bookmarkCount" : 0,
"caption" : "Toll",
"commentCount" : 1,
"creationDate" : 1.494081403379004E9,
"hoursSinceUpload" : 0,
"likeCount" : 0,
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F76192CBE-55F0-4907-889A-849E196D5796?alt=media&token=de675609-4b73-411d-b402-f1ff3db64f79",
"ratio" : 1.502732240437158,
"score" : 16.38698994684219,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-KjTHFNe1RRS8Ly6bKsA" : {
"bookmarkCount" : 1,
"bookmarks" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"caption" : "Traumhaft",
"commentCount" : 0,
"creationDate" : 1.494082976550228E9,
"hoursSinceUpload" : 0,
"likeCount" : 2,
"likes" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : true,
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F306BF7E1-9FEF-493A-ABF8-C0E061E8648F?alt=media&token=128bdd90-023a-49ac-8361-19c02c631183",
"ratio" : 1.502732240437158,
"score" : 166.6491847103437,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-KjY30xwWA2IJBwlvyzf" : {
"bookmarkCount" : 1,
"bookmarks" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"caption" : "Traumwagen",
"commentCount" : 2,
"creationDate" : 1.494163133228368E9,
"hoursSinceUpload" : 0,
"likeCount" : 2,
"likes" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : true,
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F5C83FB24-BE21-49D9-863F-039FDE34969E?alt=media&token=e7e053a0-1966-4614-afad-42cab87f7880",
"ratio" : 1.775,
"score" : 280.0086305441856,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2",
"videoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F5951720B-54F4-44C1-859C-43D8ACB98334?alt=media&token=02be7eaf-4970-4059-b07d-036a4f182b28"
}
},
"users" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : {
"email" : "user3#mail.de",
"profilText" : "Schreib etwas über dich",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2Fes5fIbnKFpX4szcCbroUqHjJg6E3?alt=media&token=ce8d8722-39bc-457a-8149-e51c837ef0a3",
"username" : "Blondine",
"username_lowercase" : "blondine"
},
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : {
"email" : "user2#mail.de",
"profilText" : "Schreib etwas über dich",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2FjlkRoaucY6Q4GBkzhor5yAAl97I2?alt=media&token=197ee89d-c328-4d04-a56e-02a9450b1720",
"username" : "Marie",
"username_lowercase" : "marie"
},
"tH3714ywXTOgGK0cxBgGvTiSDLl2" : {
"email" : "user1#mail.de",
"profilText" : "Schreib etwas über dich",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2FtH3714ywXTOgGK0cxBgGvTiSDLl2?alt=media&token=b08060a8-ef6b-4cf7-a73f-5bacd1ddada5",
"username" : "Elena",
"username_lowercase" : "elena"
}
}
}
EDIT : MORE CODE
class HomeViewController: UIViewController {
#IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
#IBOutlet weak var tableView: UITableView!
var posts = [Post]()
var users = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 521
tableView.rowHeight = UITableViewAutomaticDimension
tableView.dataSource = self
loadPost()
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
tableView?.refreshControl = refreshControl
}
func handleRefresh() {
posts.removeAll()
loadPost()
tableView.reloadData()
self.tableView?.refreshControl?.endRefreshing()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "CommentSegue" {
let commentVC = segue.destination as! CommentViewController
let postId = sender as! String
commentVC.postId = postId
}
if segue.identifier == "Home_ProfileSegue" {
let profileVC = segue.destination as! ProfileUserViewController
let userId = sender as! String
profileVC.userId = userId
}
if segue.identifier == "Home_Hashtag" {
let hashTagVc = segue.destination as! HashTagViewController
let tag = sender as! String
hashTagVc.tag = tag
}
}
func loadPost() {
API.Feed.observeFeed(withId: API.User.CURRENT_USER!.uid) { (post) in
guard let postUid = post.userId else {
return
}
self.fetchUser(uid: postUid, completed: {
self.posts.insert(post, at: 0)
self.tableView.reloadData()
})
API.Post.calculateScore(postId: post.id!, onSuccess: { (post) in
}) { (errorMessage) in
ProgressHUD.showError(errorMessage)
}
}
API.Feed.observeFeedRemoved(withId: API.User.CURRENT_USER!.uid) { (post) in
self.posts = self.posts.filter{ $0.id != post.id }
self.users = self.users.filter{$0.id != post.userId }
self.tableView.reloadData()
}
}
func fetchUser(uid: String, completed: #escaping () -> Void) {
API.User.observeUser(withId: uid, completion: {
user in
self.users.insert(user, at: 0)
completed()
})
}
}
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! HomeTableViewCell
let post = posts[indexPath.row]
let user = users[indexPath.row]
cell.post = post
cell.user = user
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
}
extension HomeViewController : HomeTableViewCellDelegate {
func goToCommentViewController(postId:String) {
performSegue(withIdentifier: "CommentSegue", sender: postId)
}
func goToProfileUserViewController(userId: String) {
performSegue(withIdentifier: "Home_ProfileSegue", sender: userId)
}
func goToHashtag(tag: String) {
performSegue(withIdentifier: "Home_Hashtag", sender: tag)
}
func goToLikesViewController(postId:String) {
performSegue(withIdentifier: "LikeSegue", sender: postId)
}
}
That VC is like the feed on Instagram where all the cells are for each post. Each post counts the users who liked it and I would like to show the likes from users who liked the observed post, not the hardcoded post.
Thank you. :)
This is what I have come up with. I tested it using your JSON, and it worked. It might be a bit different from your original code, but it should give you an idea on how to implement it. Also, the fetchUser function seemed useless so I left it out, and the username_lowercase is pointless since you can just call .lowercased() on any String.
import UIKit
import Firebase
class LikesViewController: UITableViewController {
var postId: String! // add this var
var users = Array<User>()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.loadUserLikes()
}
func loadUserLikes(){
let api = UserApi()
// changed this to var postId
api.observeUserLikes(withPostId: postId) { (uids) in
for uid in uids {
api.observeUser(withId: uid, completion: { (user) in
if let currentUser = FIRAuth.auth()?.currentUser {
if uid == currentUser.uid {
self.users.insert(user, at: 0) // This will put the current user at the start of the array, so should be at top of table view.
self.tableView.reloadData()
return
}
}
self.users.append(user)
self.tableView.reloadData()
})
}
}
}
// MARK: TableView Delegates
}
struct User {
var uid: String
var username: String
var email: String
var profileText: String
var profileImageURL: String
init?(uid: String, dict: Dictionary<String,String>) {
guard
let username = dict["username"],
let email = dict["email"],
let profileText = dict["profilText"],
let profileImageURL = dict["profileImageUrl"]
else {
return nil
}
self.uid = uid
self.username = username
self.email = email
self.profileText = profileText
self.profileImageURL = profileImageURL
}
}
class UserApi {
var REF_USERS = FIRDatabase.database().reference().child("users")
var REF_POST_USERS_LIKED = FIRDatabase.database().reference().child("LikesFromUsers")
var REF_POST = FIRDatabase.database().reference().child("posts")
func observeUser(withId uid: String, completion: #escaping (User) -> Void) {
REF_USERS.child(uid).observeSingleEvent(of: .value, with: { snapshot in
guard let dict = snapshot.value as? Dictionary<String,String> else { return }
if let user = User(uid: snapshot.key, dict: dict) {
completion(user)
} else {
print("Incomplete User Data.")
}
})
}
func observeUsers(completion: #escaping (Array<User>) -> Void) {
REF_USERS.observe(.value, with: { snapshot in
guard let dict = snapshot.value as? Dictionary<String,Dictionary<String,String>> else { return }
var users = Array<User>()
for (key, value) in dict {
if let user = User(uid: key, dict: value) {
guard let currentUser = FIRAuth.auth()?.currentUser else { return }
if user.uid != currentUser.uid {
users.append(user)
}
} else {
print("Incomplete User Data.")
}
}
completion(users)
})
}
func observeUserLikes(withPostId id: String , completion: #escaping (Array<String>) -> Void) {
REF_POST_USERS_LIKED.child(id).observeSingleEvent(of: .value, with: { snapshot in
guard let dict = snapshot.value as? Dictionary<String,Bool> else { return }
var users = Array<String>() // Array of user ids who liked the post.
for (key, value) in dict {
if value == true {
users.append(key)
}
}
completion(users)
})
}
// I've added this to get all the posts.
func observePosts(completion: #escaping (Array<Post>) -> Void) {
REF_POST.observe(.value, with: { snapshot in
guard let dict = snapshot.value as? Dictionary<String,Dictionary<String,Any>> else { return }
var posts = Array<Post>()
for (key, value) in dict {
if let post = Post(uid: key, dict: value) {
posts.append(post)
} else {
print("Incomplete Post Data.")
}
}
completion(posts)
})
}
}
This is the Post View Controller that I have made to test the Likes View Controller.
struct Post {
var uid: String
var photoUrl: String
var ratio: Double
var score: Double
var creationDate: Date
init?(uid: String, dict: Dictionary<String,Any>) {
guard
let photoUrl = dict["photoUrl"] as? String,
let ratio = dict["ratio"] as? Double,
let score = dict["score"] as? Double,
let creationDate = dict["creationDate"] as? TimeInterval
else {
return nil
}
self.uid = uid
self.photoUrl = photoUrl
self.ratio = ratio
self.score = score
self.creationDate = Date(timeIntervalSince1970: creationDate)
}
}
struct Comment {
var uid: String
var user: User
var comment: String
}
class PostsViewController: UITableViewController {
var posts = Array<Post>()
override func viewDidLoad() {
super.viewDidLoad()
let api = UserApi()
api.observePosts { (posts) in
self.posts = posts
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
let post = self.posts[indexPath.row]
cell.textLabel?.text = post.uid
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Just for testing, I have it show the likes view controller when the cell is tapped.
// Although you will probably have this as a button, so just copy this code into the action.
let post = posts[indexPath.row]
guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "LikesViewController") as? LikesViewController else { return }
vc.postId = post.uid
self.navigationController?.pushViewController(vc, animated: true)
}
}
These screenshots only show the uid of the post or user, but you'll be able to change this to show all the required data.
i am getting some data from one url and i am try to display in table view. before that i directly used all array , search, sorting.Its worked well.But now, when i create separate class for my table view i am getting this error
Type 'BusinessData' has no member 'sortUsingComparator' in my sorting function.Here i gave 3 button action.Inside that button action i declaring this sorting code.But now i am getting this error.
my bussinessData.swift class
import UIKit
class BusinessData {
var BusinessName: String?
var Address: String?
var Rating: Float?
var ContactNumber: String?
init(json: NSDictionary) {
self.BusinessName = json["business_name"] as? String
self.Address = json["location"] as? String
self.Rating = json["__v"] as? Float
self.ContactNumber = json["phone_no"] as? String
}
}
My viewcontroller.swift code:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var isTapped:Bool? // cell tap checking bool
var selectedIndex:NSIndexPath?
#IBOutlet weak var RightMenu: UIView!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView! // UITable view declaration
var arrDict = [BusinessData]() // array to store the value from json
var isSearching:Bool?
var arrSearch:NSMutableArray=[]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.jsonParsingFromURL() // call the json method
searchBar.returnKeyType = UIReturnKeyType.Done;
searchBar.hidden = true;
// nib for custom cell (table view)
let nib = UINib(nibName:"customCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
indicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 90, 90))
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
indicator.center = self.view.center
indicator.color = UIColor .redColor()
self.view.addSubview(indicator)
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "searchMethod:", name: "search", object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: "endSearch", name: "endSearch", object: nil);
}
// web services method
func jsonParsingFromURL ()
{
let url:NSURL = NSURL(string: "http://sample url/Fes?current_location=toronto&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyIkX18")!
if let JSONData = NSData(contentsOfURL: url)
{
if let json = (try? NSJSONSerialization.JSONObjectWithData(JSONData, options: [])) as? NSDictionary
{
if let reposArray = json["data"] as? [NSDictionary]
{
for item in reposArray
{
let itemObj = item as? Dictionary<String,AnyObject>
let b_type = itemObj!["business_type"]?.valueForKey("type")
if (b_type as? String == "Taxis")
{
arrDict.append(BusinessData(json: item))
}
}
}
}
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
if(isSearching == true)
{
return arrSearch.count;
}
return self.arrDict.count
}
// number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
// height for each cell
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return cellSpacingHeight
}
// calling each cell based on tap and users ( premium / non premium )
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell:customCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
if(isSearching == true)
{
cell.vendorName.text = arrDict[indexPath.section].BusinessName
cell.vendorAddress.text = arrDict[indexPath.section].Address
cell.VendorRating.rating = arrDict[indexPath.section].Rating!
}
else
{
cell.vendorName.text = arrDict[indexPath.section].BusinessName
cell.vendorAddress.text = arrDict[indexPath.section].Address
cell.VendorRating.rating = arrDict[indexPath.section].Rating!
}
return cell
}
// MARK:
// MARK: Sort Method
#IBAction func sortByRevBtnPress(sender: AnyObject)
{
self.indicator.startAnimating()
self.indicator.hidden = false
RightMenu.hidden = true
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(1 * NSEC_PER_SEC)), dispatch_get_main_queue()){
self.indicator.stopAnimating()
self.indicator.hidden = true
};
self.tableView.reloadData()
}
#IBAction func sortByAZBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["business_name"] as? String, name2 = dict2["business_name"] as? String
{
return name1.compare(name2)
}
return .OrderedAscending
}
self.tableView.reloadData()
}
#IBAction func sortByRatingBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["rating"] as? String, name2 = dict2["rating"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
#IBAction func sortByRecentBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["created_at"] as? String, name2 = dict2["created_at"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
// MARK:
// MARK: Search Method
func endSearch()
{
if(isSearching == false)
{
isSearching = true;
searchBar.hidden = false;
yConstraint.constant = 47;
self.view.layoutIfNeeded();
}
else
{
isSearching = false;
searchBar.hidden = true;
tableView.reloadData();
yConstraint.constant = 3;
self.view.layoutIfNeeded();
self.view.endEditing(true);
}
}
func searchMethod(notification:NSNotification)
{
if(isSearching == true)
{
isSearching = false;
searchBar.hidden = true;
tableView.reloadData();
yConstraint.constant = 3;
self.view.layoutIfNeeded();
self.view.endEditing(true);
}
else
{
isSearching = true;
searchBar.hidden = false;
yConstraint.constant = 47;
self.view.layoutIfNeeded();
}
}
// MARK:
// MARK: SearchBar Method
func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
arrSearch = [];
for(var i=0;i<arrDict.count;i++)
{
if((BusinessData.objectAtIndex(i).objectForKey("name")?.lowercaseString?.containsString(searchText.lowercaseString)) == true)
{
arrSearch.addObject(BusinessData.objectAtIndex(i));
}
}
tableView.reloadData();
}
func searchBarSearchButtonClicked(searchBar: UISearchBar)
{
self.view.endEditing(true);
isSearching = false;
searchBar.hidden = true;
tableView.reloadData();
yConstraint.constant = 3;
self.view.layoutIfNeeded();
}
}
I am getting error in this these button action method:
#IBAction func sortByAZBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["business_name"] as? String, name2 = dict2["business_name"] as? String
{
return name1.compare(name2)
}
return .OrderedAscending
}
self.tableView.reloadData()
}
#IBAction func sortByRatingBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["rating"] as? String, name2 = dict2["rating"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
#IBAction func sortByRecentBtnPress(sender: AnyObject)
{
RightMenu.hidden = true
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
if let name1 = dict1["created_at"] as? String, name2 = dict2["created_at"] as? String
{
return name2.compare(name1)
}
return .OrderedDescending
}
self.tableView.reloadData()
}
In every method i am getting this error Type 'BusinessData' has no member 'sortUsingComparator'..In this below line :
BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in
Please help me out
Thanks
BusinessData is a model class. It looks like what you really want to do is to sort var arrDict = [BusinessData]() - an array of BusinessData instances.
Your current code BusinessData.sortUsingComparator { (dict1, dict2) -> NSComparisonResult in is trying to call a class method sortUsingComparator on BusinessData model class and expects to get 2 dictionaries back.
What you want is something more like:
arrDict.sortUsingComparator { (b1, b2) -> NSComparisonResult in
where b1 and b2 are instances of BusinessData, not dictionaries.