EXC Bad Instruction Error Swift - ios

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()
}

Related

swift passing data from Table View cells with segment to another view controller

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.

CollectionView updates and duplicated sequentially in my chat view. (Swift 4.2, Xcode)(MessengerKit)

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

Not getting directions router when didSelectRow is tapped in Swift?

I am creating an app where I have a detailViewController where there is an address of place and when the user clicks on the address - it opens the apple maps (which what I want) but it does not show that router as a destination to go to that address. I am getting to: -118.277.... and from myLocation (which is good), except the to part & it also tells directions not available. So, I want the address that didSelectRow is pressed to bring the destination directions in apple maps when clicked. thank you for the help.
UPDATED I just debug and created a watch for place.location?.coordinate I see some result but they are just longitude and latitude. But, I want to show the address instead of lat & long.
Here is my code:
import UIKit
import Social
import CoreLocation
class DetailsViewController: BaseViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
var nearMeIndexSelected = NearMeIndexTitle()
var place: Place!
var coordinate :CLLocationCoordinate2D?
var nearMeRequest : NearMeRequest!
var locationManager = CLLocationManager()
let infoCellId = "info-cell"
let interactiveCellId = "interactive-cell"
let directionsSegueId = "directions-segue"
let gallerySegueId = "gallery-segue"
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var annotation: ARAnnotation!
override func viewDidLoad() {
super.viewDidLoad()
if self.place != nil {
self.title = place.placeName
self.tableView.delegate = self
self.tableView.dataSource = self
self.loadDetailInfo()
print("Place is not nil")
} else {
print("Place is nil")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 4
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 4
}
else if section == 1 {
return 0
}
else if section == 2 {
return 1
}
else {
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cellId = infoCellId
if indexPath.section != 0 {
cellId = interactiveCellId
}
let cell: UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellId)! as UITableViewCell
var key = "Not Available"
var value = "Not Available"
if indexPath.section == 0 {
if indexPath.row == 0 {
key = "Name"
if self.place.placeName.characters.count > 0 {
value = self.place.placeName
}
} else if indexPath.row == 1 {
key = "Address"
if let address = self.place.address {
if address.characters.count > 0 {
value = address
}
}
} else if indexPath.row == 2 {
key = "Phone number"
if let phoneNumber = self.place.phoneNumber {
if phoneNumber.characters.count > 0 {
value = phoneNumber
}
}
} else if indexPath.row == 3 {
key = "Website"
if let website = self.place.website {
if website.characters.count > 0 {
value = website
}
}
}
}
else if indexPath.section == 2 {
key = "Get Directions"
} else {
key = "Photos of \(self.place.placeName)"
}
if indexPath.section == 0 {
cell.textLabel?.text = key
cell.detailTextLabel?.text = value
} else {
cell.textLabel?.text = key
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
if indexPath.row == 1 {
print("it works!")
if let coordinate = place.location?.coordinate {
if let url = URL(string:"http://maps.apple.com/maps?daddr=\(coordinate.longitude),\(coordinate.latitude)") {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}
if indexPath.row == 2 {
guard let phoneNumber = self.place.phoneNumber,
phoneNumber.count > 0,
let url = URL(string: "tel:\(phoneNumber.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)")
else { return }
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
} else { return }
}
else if indexPath.section == 2 {
self.performSegue(withIdentifier: directionsSegueId, sender: self)
} else {
if let photoReferences = self.place.photoReferences {
if photoReferences.count != 0 {
self.performSegue(withIdentifier: gallerySegueId, sender: self)
return
}
}
// View Photo button
let alertController = UIAlertController(title: "No photos", message: "Sorry, but there are no photos found for this place.", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Ok", style: .cancel) { action in
// ...
}
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return " Info"
}
else if section == 1{
//return " Request a Uber"
return ""
}
else if section == 2 {
return " Navigation"
} else {
return " Photo"
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == directionsSegueId {
let controller = segue.destination as! DirectionsViewController
controller.place = self.place
} else if segue.identifier == gallerySegueId {
let navController = segue.destination as! UINavigationController
let galleryController = navController.viewControllers[0] as! GalleryViewController
galleryController.place = self.place
}
}
func generatePlaceUrl() -> URL {
let placeNamePlus = self.place.placeName.replacingOccurrences(of: " ", with: "+")
var urlString = "https://www.google.com/maps/place/" + placeNamePlus
if let addressPlus = self.place.address?.replacingOccurrences(of: " ", with: "+") {
urlString = urlString + "+" + addressPlus
}
let url = URL.init(string: urlString)
if let finalUrl = url {
return finalUrl
}
return URL.init(string: "https://www.maps.google.com")!
}
func loadDetailInfo() {
let loader = PlacesLoader()
self.activityIndicator.startAnimating()
self.tableView.isHidden = true
loader.loadDetailInformation(forPlace: self.place) { (dictionary, error) in
guard dictionary != nil else {
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.tableView.isHidden = false
self.tableView.reloadData()
}
return
}
if let resultDictionary = dictionary!["result"] as? NSDictionary {
self.place.address = (resultDictionary["formatted_address"] as? String)!
self.place.phoneNumber = resultDictionary["formatted_phone_number"] as? String
self.place.website = resultDictionary["website"] as? String
if let photosArr = resultDictionary["photos"] as? [NSDictionary] {
for photoDict in photosArr {
let photoReference = photoDict["photo_reference"] as? String
if self.place.photoReferences == nil {
self.place.photoReferences = [String]()
}
self.place.photoReferences?.append(photoReference!)
}
}
}
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.tableView.isHidden = false
self.tableView.reloadData()
}
}
}
}
Your latitude and longitude values are the wrong way round, try this:
if let url = URL(string:"http://maps.apple.com/maps?daddr=\(coordinate.latitude),\(coordinate.longitude)") {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}

Swift Segmented Control Change Index Event, TableView not updating

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

Update TableViewCell with Asynchronous data

I have a tableViewCell that contains 8 images total divided into two blocks (4 images in each block). These images are downloaded asynchronously and stored into an array and then used in the the tableViewCell's cellForRowAtIndexPath to populate the images. I reload the tableView when all the images for one block has been added to the array in the dictionary (groupTOImages). The way I am doing it, I am getting out of order inconsistent results with the loading of the data. Some images are loaded into places where they shouldn't be. Is there a way to download the images and get consistent results in the tableViewCell.
var groupNames = [NSManagedObject]()
var groupTOPeople = [NSManagedObject: [String]]()
var groupTOImages = [NSManagedObject: [UIImage]]()
func getGroups() {
...
for group in groupNames {
groupTOImages[group] = []
if let people = groupTOPeople[group] {
var mycount = 0
for peeps in people {
InstagramEngine.sharedEngine().getUserDetails(peeps, withSuccess: { user in
if let ppic = user.profilePictureURL {
let picUrl = ppic.absoluteString
print(picUrl)
ImageLoader.sharedLoader.imageForUrl(picUrl) { (image, url) -> () in
self.groupTOImages[group]?.append(image!)
mycount++
if mycount == people.count {
self.tableView.reloadData()
}
}
} else {
self.groupTOImages[group]?.append(UIImage())
mycount++
if mycount == people.count {
self.tableView.reloadData()
}
}
}, failure: nil )
}
}
}
var counter = 0
var groupCount = 0
var groupCounter = 0
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellInfo = GroupCellsArray[indexPath.section]
...
case .userGroups:
let cell = tableView.dequeueReusableCellWithIdentifier(cellInfo.description, forIndexPath: indexPath) as! GroupTableViewCell
if groupNames.count > 0 {
var gp = groupNames[groupCounter]
switch counter {
case 0:
cell.firstTitle.text = (gp.valueForKey("name") as! String)
if let ourImages = groupTOImages[gp] {
for image in ourImages {
print(image.description)
print("groupCount \(groupCounter)")
cell.firstUserButtons[groupCount].layer.borderWidth = 0
cell.firstUserButtons[groupCount].setImage(image, forState: .Normal)
groupCount++
if groupCount == ourImages.count {
groupCount = 0
counter++
groupCounter++
gp = groupNames[groupCounter]
}
}
}
case 1:
if let title = gp.valueForKey("name") as? String {
cell.secondTitle.text = title
if let ourImages = groupTOImages[gp] {
for image in ourImages {
cell.secondUserButtons[groupCount].layer.borderWidth = 0
cell.secondUserButtons[groupCount].setImage(image, forState: .Normal)
groupCount++
if groupCount == ourImages.count {
groupCount = 0
counter = 0
groupCounter++
gp = groupNames[groupCounter]
}
}
}
} else {
cell.secondTitle.text = "Title"
}
default:
break
}
Each row looks like the picture below:
Code using ImageLoader in cellForRowAtIndexPath:
var counter = 0
for group in groupNames {
print("in the second")
groupTOImages[group] = []
if let people = groupTOPeople[group] {
var mycount = 0
for peeps in people {
InstagramEngine.sharedEngine().getUserDetails(peeps, withSuccess: { user in
if let ppic = user.profilePictureURL {
let picUrl = ppic.absoluteString
self.groupTOImages[group]?.append(picUrl)
counter++
mycount++
if counter == self.groupNames.count && mycount == people.count
{
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
} else {
self.groupTOImages[group]?.append(nil)
counter++
mycount++
if counter == self.groupNames.count && mycount == people.count
{
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}, failure: nil )
}
}
if groupNames.count > 0 {
var gp = groupNames[groupCounter]
print("counter!!!!")
print("groupCount \(counter)")
switch counter {
case 0:
if let ourImages = groupTOImages[gp] {
cell.firstTitle.text = (gp.valueForKey("name") as! String)
print(cell.firstTitle.text)
for image in ourImages {
if let url = image {
print("I get in here")
ImageLoader.sharedLoader.imageForUrl(url) { (image, url) -> () in
cell.firstUserButtons[self.groupCount].layer.borderWidth = 0
cell.firstUserButtons[self.groupCount].setImage(image, forState: .Normal)
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
} else {
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
}
}
case 1:
if let title = gp.valueForKey("name") as? String {
cell.secondTitle.text = title
if let ourImages = groupTOImages[gp] {
for image in ourImages {
if let url = image {
ImageLoader.sharedLoader.imageForUrl(url) { (image, url) -> () in
cell.secondUserButtons[self.groupCount].layer.borderWidth = 0
cell.secondUserButtons[self.groupCount].setImage(image, forState: .Normal)
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
} else {
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter = 0
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
}
}
} else {
cell.secondTitle.text = "Title"
}
You should replace the self.tableView.reloadData() with
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
Hope this helps!

Resources