how to customizing swift firabase didselectedrowat - ios

hello i am begginer to swift i get an error "Cannot assign value of type 'Character' to type '[String]'" how can i fix that my brain is now lost in this code blog enter code here
import UIKit
import FirebaseFirestore
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
class PhoneViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var phoneModelText = [String]()
var imeiAdressText = [String]()
var userNameText = [String]()
var idText = [String]()
var phoneNumberText = [String]()
var detailsText = [String]()
var dateText = [String]()
var priceText = [String]()
var adressText = [String]()
var selectedPhoneModelText = ""
var selectedimeiAdressText = ""
var selecteduserNameText = ""
var selectedidText = ""
var selectedphoneNumberText = ""
var selecteddetailsText = ""
var selecteddateText = ""
var selectedpriceText = ""
var selectedadressText = ""
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
tableView.dataSource = self
tableView.delegate = self
getdata()
}
func makeAlert(titleInput: String, messageInput : String) {
let alert = UIAlertController(title: titleInput, message: messageInput, preferredStyle: UIAlertController.Style.alert)
let okButton = UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil)
alert.addAction(okButton)
present(alert, animated: true, completion: nil)
}
func fetchBook(documentId: String) {
let db = Firestore.firestore()
let docRef = db.collection("Databases").document(documentId)
docRef.getDocument { document, error in
if let error = error as NSError? {
self.makeAlert(titleInput: "alert", messageInput: "\(error.localizedDescription)")
}
else {
if let document = document {
let id = document.documentID
let data = document.data()
let phonemodel = data?["phoneName"] as? String ?? ""
let imeiadress = data?["imeiNumberText"] as? Int ?? 0
let username = data?["userNameText"] as? String ?? ""
let idcard = data?["idCardtext"] as? Int ?? 0
let phonenumber = data?["phoneNumberText"] as? Int ?? 0
let adress = data?["adressNameText"] as? String ?? ""
let details = data?["detailSectionText"] as? String ?? ""
let date = data?["currentDateText"] as? String ?? ""
let price = data?["priceValueText"] as? Int ?? 0
let image = data?["imageurl"] as? String ?? ""
DispatchQueue.main.async {
self.selectedphoneNumberText = phonemodel
self.phoneModelText.text = phonemodel
self.imeiAdressText.text = String(imeiadress)
self.userNameText.text = username
self.idText.text = String(idcard)
self.phoneNumberText.text = String(phonenumber)
self.adressText.text = adress
self.detailsText.text = details
self.dateText.text = date
self.priceText.text = String(price)
}
}
}
}
}
}
extension PhoneViewController : UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return phoneModelText.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = phoneModelText[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// how i customizing there
performSegue(withIdentifier: "toPhoneListView", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toPhoneListView" {
let destinationVC = segue.destination as! PhoneListViewController
destinationVC.selectedPhoneModelText
destinationVC.selectedimeiAdressText
destinationVC.selecteduserNameText
destinationVC.selectedidText
destinationVC.selectedphoneNumberText
destinationVC.selecteddetailsText
destinationVC.selecteddateText
destinationVC.selectedpriceText
destinationVC.selectedadressText
}
}
}

This is how your phoneModelText is defined
var phoneModelText = [String]()
that indicates that phoneModelText is an array of strings, so it would look something like this
phoneModelText[0] = "Some String"
phoneModelText[1] = "Another string"
but then later you're attempting to assign string to that array
self.phoneModelText.text = phonemodel
And that's not how arrays work. If you want to add phoneModel to the array it would be this
self.phoneModelText.append(phoneModel) //assume phoneModel = "yet another string"
so then the array would look like this
phoneModelText[0] = "Some String"
phoneModelText[1] = "Another string"
phoneModelText[2] = "yet another string"
In general I would suggest naming your vars so they more represent what they contain - instead of phoneModelText, call it phoneModelTextArray. That wil reduce confusion and make the code more readable.
As far as a solution, it's not clear why there are a bunch of arrays
var phoneModelText = [String]()
var imeiAdressText = [String]()
var userNameText = [String]()
but I suggest changing all of that around. One option is to define a class with properties and then have an array of classes
class ContactClass {
var id = ""
var phoneText = ""
var imeiAdressText = ""
var userNameText = ""
}
and then an array of classes within your controller
var contactArray = [ContactClass]()
and then lastly, when reading data from Firebase, instantiate the class, populate the class properties and add the class to the array
else {
if let document = document {
let contact = ContactClass()
contact.id = document.documentID
contact.phoneText = data?["phoneName"] as? String ?? ""
contact.imeiAdressText = data?["imeiNumberText"] as? Int ?? 0
contact.userNameText = data?["userName"] as? String ?? ""
self.contactArray.append(contact)

Related

How can i get global defined like "dictionary.count" return value?

I'm trying to fetch specific user messages from Firebase Real-Time database.I want to fill chatLogTableView with the user messages.I'm fetching user messages datas from firebase with fetchCurrentUserMessages() function.
In this function :
self.messagesDatas.append(message)
print(self.messagesDatas)
When i try to print the self.messagesDatas its okay.But when the tableview trying to retrieve self.messagesDatas.count for numberOfRowsInSection i'm getting 0 count.Why this is happening ?
Here is my code :
import UIKit
import Firebase
class ChatLogCustomCell: UITableViewCell {
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: UILabel!
}
class ChatLogViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var chatLogTableView: UITableView!
#IBOutlet weak var messageTextField: UITextField! // bu kismi elle yazman gerekebilir cunku xcode bu messagetextfield i sanki view in icinde oldugu icin table view icinde algilayamayabilir
#IBOutlet weak var backButton: UINavigationItem!
var usersDataFromChatScreen = [User]()
var selectedUserToIDFromChatScreen = ""
var isTeacherFromChatScreen = ""
var messagesDatas = [Message]()
var messagesDictionary = [String : Message]()
override func viewDidLoad() {
super.viewDidLoad()
chatLogTableView.delegate = self
chatLogTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messagesDatas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = chatLogTableView.dequeueReusableCell(withIdentifier: "chatLogCell") as! ChatLogCustomCell
let message = messagesDatas[indexPath.row]
cell.leftLabel.text = message.text
cell.rightLabel.text = message.text
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
#IBAction func sendButtonTouchOnInside(_ sender: Any) {
let ref = Database.database().reference().child("messages")
let childRef = ref.childByAutoId()
let toID = selectedUserToIDFromChatScreen
Auth.auth().addStateDidChangeListener { (auth, user) in
let fromID = auth.currentUser?.uid
let values = ["text" : self.messageTextField.text, "toID" : toID, "fromID" : fromID] as [String : Any]
childRef.updateChildValues(values) { (error, ref) in
if error != nil {
print(error ?? "")
return
}
guard let messageID = childRef.key else { return }
let userMessagesRef = Database.database().reference().child("user-messages").child(fromID!).child(messageID)
userMessagesRef.setValue(1)
let recipientUserMessagesRef = Database.database().reference().child("user-messages").child(toID).child(messageID)
recipientUserMessagesRef.setValue(1)
}
}
}
func fetchCurrentUserMessages() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
if self.isTeacherFromChatScreen == "no" {
let ref = Database.database().reference().child("user-messages").child(uid)
ref.observe(.childAdded) { (snapshot) in
let messageID = snapshot.key
let messagesRef = Database.database().reference().child("messages").child(messageID)
messagesRef.observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else {
return
}
let message = Message()
let toID = dictionary["toID"] as? String ?? "toID not found"
let messageText = dictionary["text"] as? String ?? "Text not found"
let fromID = dictionary["fromID"] as? String ?? "fromID not found"
message.toID = toID
message.text = messageText
message.fromID = fromID
self.messagesDatas.append(message)
print(self.messagesDatas.count)
}
}
}
else {
}
}
}
Reload your tableview when you get data from server
func fetchCurrentUserMessages() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
if self.isTeacherFromChatScreen == "no" {
let ref = Database.database().reference().child("user-messages").child(uid)
ref.observe(.childAdded) { (snapshot) in
let messageID = snapshot.key
let messagesRef = Database.database().reference().child("messages").child(messageID)
messagesRef.observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else {
return
}
let message = Message()
let toID = dictionary["toID"] as? String ?? "toID not found"
let messageText = dictionary["text"] as? String ?? "Text not found"
let fromID = dictionary["fromID"] as? String ?? "fromID not found"
message.toID = toID
message.text = messageText
message.fromID = fromID
self.messagesDatas.append(message)
print(self.messagesDatas.count)
DispatchQueue.main.async {
chatLogTableView.reloadData()
}
}
}
}
else {
}
}

Button in the table cell not working upon tapping

I am using below code for the UITableView, in every cell there are two buttons configured to perform certain actions as shown in the code. Earlier it was working fine, but now As I update this code to new version of Xcode it is not working, whenever I tap on the cell or the button in the cell it doesn't perform any action, neither it shows any error, but it just darkens the half of the cell with grey colour?
Xcode earlier was 10 and now 11, swift 5 version same in both cases
There is one fixed cell at the top and then there is list of cells as per the number of documents in the database
What could be the issue?
for information I am using Swift IOS and cloud firestore database
class HomeViewController: UITableViewController {
var posts = [Post]()
var db: Firestore!
var scores1 = [Scores]()
var postAuthorId:String = ""
var postAuthorname:String = ""
var CommentAuthorName:String = ""
var PostTitle:String = ""
var postAuthorGender:String = ""
var postAuthorEmail:String = ""
var postAuthorfullname:String = ""
var postAuthorSpinnerC:String = ""
var postContent:String = ""
var postCategory:String = ""
var postAuthorPicUrl:String = ""
var postTimeStamp:String = ""
var l11:Int = 0
var postKey:String = ""
private var documents: [DocumentSnapshot] = []
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
tableView.dataSource = self
tableView.delegate = self
retrieveAllPosts()
getuserscores()
var AViewController: UIViewController = UIViewController()
var MyTabBarItem: UITabBarItem = UITabBarItem(title: nil, image: UIImage(named: "pencil")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal), selectedImage: UIImage(named: "pencil"))
AViewController.tabBarItem = MyTabBarItem
// Do any additional setup after loading the view.
// navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(handleLogout))
}
func getuserscores(){
let userRef = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid)
userRef.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
let l1 = document.get("l1") as! Int
let l2 = document.get("l2") as! Int
let l3 = document.get("l3") as! Int
let l4 = document.get("l4") as! Int
let newScores = Scores(_l1: l1, _l2: l2, _l3: l3, _l4: l4)
self.scores1.append(newScores)
}
self.tableView.reloadData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func retrieveAllPosts(){
let postsRef = Firestore.firestore().collection("posts").order(by: "timestamp", descending: true).limit(to: 50)
postsRef.getDocuments { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
let username = data["post_author_username"] as? String ?? ""
let postTitle = data["postTitle"] as? String ?? ""
let postcategory = data["postcategory"] as? String ?? ""
let postContent = data["postContent"] as? String ?? ""
let postAuthorProfilePicUrl = data["post_user_profile_pic_url"] as? String ?? ""
let postAuthorSpinnerC = data["post_author_spinnerC"] as? String
let newSourse = Post(_documentId: document.documentID, _username: username, _postTitle: postTitle, _postcategory: postcategory, _postContent: postContent, _postuserprofileImagUrl: postAuthorProfilePicUrl, _postAuthorSpinncerC: postAuthorSpinnerC)
self.posts.append(newSourse)
}
self.tableView.reloadData()
}
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.estimatedRowHeight = 200
tableView.rowHeight = UITableView.automaticDimension
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return scores1.count + posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 && scores1.count == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SmileMiles") as! ScoresCellInHomeScreen
cell.set(scores: scores1[indexPath.row])
return cell
} else if posts.count > (indexPath.row - 1 ) {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.btnComment.tag = indexPath.row - 1
cell.btnComment.addTarget(self, action: #selector(toComments(_:)), for: .touchUpInside)
cell.favoritebutton.tag = indexPath.row - 1
cell.favoritebutton.addTarget(self, action: #selector(favupdate(_:)), for: .touchUpInside)
cell.set(post: posts[indexPath.row - 1 ])
return cell
} else {
return UITableViewCell()
}
}
#objc func favupdate(_ sender: AnyObject) {
let commentbutton = sender as! UIButton
let post = posts[commentbutton.tag]
postKey = post._documentId // or what key value it is
let userMarkRef = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid).collection("marked_posts").document(postKey)
let postRef = Firestore.firestore().collection("posts").document(postKey)
postRef.getDocument{(document, error) in
if let document = document, document.exists{
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
self.postAuthorId = document.get("post_author_id") as! String
self.postAuthorname = document.get("post_author_username") as! String
self.PostTitle = document.get("postTitle") as! String
self.postContent = document.get("postContent") as! String
self.postAuthorEmail = document.get("post_author_email") as! String
self.postCategory = document.get("postcategory") as! String
self.postAuthorfullname = document.get("post_author_fullname") as! String
self.postAuthorGender = document.get("post_author_gender") as! String
self.postAuthorPicUrl = document.get("post_user_profile_pic_url") as! String
// let l11:Bool = document.get("l1") as! Bool
// self.postTimeStamp = document.get("post_timeStamp") as! String
self.postAuthorSpinnerC = document.get("post_author_spinnerC") as! String
}
let postObject = [
"post_author_gender": self.postAuthorGender,
// "post_author_dateOfBirth": self.dateOfBirth,
"post_author_spinnerC": self.postAuthorSpinnerC,
"post_author_fullname": self.postAuthorfullname,
"post_author_id": self.postAuthorId,
"post_author_username": self.postAuthorname,
"post_author_email": self.postAuthorEmail,
"postTitle": self.PostTitle,
"postcategory": self.postCategory,
"postContent": self.postContent,
// "post_timestamp": FieldValue.serverTimestamp(),
"post_user_profile_pic_url":self.postAuthorPicUrl,
"post_id": self.postKey
] as [String : Any]
userMarkRef.setData(postObject, merge: true) { (err) in
if let err = err {
print(err.localizedDescription)
}
print("Successfully set new user data")
}
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 150
}
else{
return UITableView.automaticDimension
}
}
#objc func toComments(_ sender: AnyObject) {
let commentbutton = sender as! UIButton
let post = posts[commentbutton.tag]
postKey = post._documentId // or what key value it is
print(postKey + "hello")
performSegue(withIdentifier: "toCommentsList", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "toCommentsList"){
var vc = segue.destination as! CommentListViewController
vc.postId = postKey
}
}
}
Do this in tableview cellForRowAt function before return cell:
cell.selectionStyle = .none
return cell
this will fix the issue

Swift/Firebase - Unable to retrieve data in order that it was entered?

Having a problem retrieving data from Firebase in the same order that it was entered. I have tried this a number of ways using different variations of .valueAdded & .value to get this back in the same order but having no luck. Perhaps the way in which I am modelling this data is incorrect? Any help with this would be great. Thanks.
This is my Firebase Structure :
This is my data model:
struct RentalObjects {
var title = [String]()
var rentalType = [String]()
var dateAval = [String]()
var location = [String]()
var price = [String]()
var bond = [String]()
var pets = [String]()
var descripton = [String]()
}
This is my table view VC :
import UIKit
import FirebaseDatabase
class RentalTableViewVC: UIViewController, UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var rentalImage: UIImageView!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var rentalTitle: UILabel!
#IBOutlet weak var rentalPrice: UILabel!
var rentalsObject = RentalObjects()
var databaseRef:DatabaseReference?
var handle: DatabaseHandle?
var arrayOfTitles = [String?]()
var arrayOfBond = [String?]()
var arrayOfDateAval = [String?]()
var arrayOfDes = [String?]()
var arrayOfLocation = [String?]()
var arrayOfPets = [String?]()
var arrayOfPrice = [String?]()
var arrayOfRentalType = [String?]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rentalsObject.title.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
cell.textLabel?.text = ("Title: \(rentalsObject.title[indexPath.row]), DateAval: \(rentalsObject.dateAval[indexPath.row])")
return cell
}
#IBAction func backPressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.dataSource = self
databaseRef = Database.database().reference().child("Rentals")
databaseRef?.observe(.childAdded, with: { (snapshot) in
if let dictonary = snapshot.value as? [String: AnyObject] {
print(snapshot)
switch snapshot.key {
case "bond" :
_ = dictonary.map{self.rentalsObject.bond.append(($0.value as? String)!)}
// print(self.arrayOfBond)
case "dateAval" :
_ = dictonary.map{self.rentalsObject.dateAval.append(($0.value as? String)!)}
case "description" :
_ = dictonary.map{self.rentalsObject.descripton.append(($0.value as? String)!)}
case "location" :
_ = dictonary.map{self.rentalsObject.location.append(($0.value as? String)!)}
case "pets" :
_ = dictonary.map{self.rentalsObject.pets.append(($0.value as? String)!)}
case "price" :
_ = dictonary.map{self.rentalsObject.price.append(($0.value as? String)!)}
case "rentalType" :
_ = dictonary.map{self.rentalsObject.rentalType.append(($0.value as? String)!)}
case "title" :
_ = dictonary.map{self.rentalsObject.title.append(($0.value as? String)!)}
print(self.rentalsObject.title)
// _ = dictonary.map{self.arrayOfTitles.append($0.value as? String)}
// print(self.arrayOfTitles)
default:
break
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
}
This is an example of the output from my tableView. I am trying to get this out in the same order it came in, in this example, 1,2,3,4,5. When I add in data from the other variables to this output they all become mixed up for some reason.
This is the code where the data is sent to firebase:
class AvertisingVC: UIViewController {
#IBOutlet weak var titleField: UITextField!
#IBOutlet weak var rentalTypeField: UITextField!
#IBOutlet weak var dateField: UITextField!
#IBOutlet weak var locationField: UITextField!
#IBOutlet weak var priceField: UITextField!
#IBOutlet weak var bondField: UITextField!
#IBOutlet weak var petsAllowedField: UITextField!
#IBOutlet weak var detailedDescription: UITextField!
var databaseRef:DatabaseReference? //reference to firebase dba
override func viewDidLoad() {
super.viewDidLoad()
databaseRef = Database.database().reference().child("Rentals") //can add .child(string:root) to add root dir to dba
}
#IBAction func backBtnPressed(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func submitForm(_ sender: Any) { // Send data to firebase on submit
if titleField.text != nil {
databaseRef?.child("title").childByAutoId().setValue(titleField.text)
titleField.text = ""
}
if rentalTypeField.text != nil {
databaseRef?.child("rentalType").childByAutoId().setValue(rentalTypeField.text)
rentalTypeField.text = ""
}
if dateField.text != nil {
databaseRef?.child("dateAval").childByAutoId().setValue(dateField.text)
dateField.text = ""
}
if locationField.text != nil {
databaseRef?.child("location").childByAutoId().setValue(locationField.text)
locationField.text = ""
}
if priceField.text != nil {
databaseRef?.child("price").childByAutoId().setValue(priceField.text)
priceField.text = ""
}
if bondField.text != nil {
databaseRef?.child("bond").childByAutoId().setValue(bondField.text)
bondField.text = ""
}
if petsAllowedField.text != nil {
databaseRef?.child("pets").childByAutoId().setValue(petsAllowedField.text)
petsAllowedField.text = ""
}
if detailedDescription.text != nil {
databaseRef?.child("description").childByAutoId().setValue(detailedDescription.text)
detailedDescription.text = ""
}
let alertController = UIAlertController(title: "Success!", message: "You have successfully listed a rental", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Close Alert", style: .default, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
}
When data is interpreted from network data, swift doesn't guarantee the order of the interpreted values if they're ordered in an array or dictionary. You'd have to order the values yourself, or update a cache device-side, and sort that cache each time it is updated.
There's many ways to this simply, or intricately for various use-cases. But looking at your's, i'd add a sort on wherever you're reading the tableView's datasource, before you call the delegate and datasource methods. Taking your example, if you sorted by date:
override func viewDidLoad() {
super.viewDidLoad()
databaseRef = Database.database().reference().child("Rentals")
databaseRef?.observe(.childAdded, with: { (snapshot) in
if let dictonary = snapshot.value as? [String: AnyObject] {
print(snapshot)
switch snapshot.key {
case "bond" :
_ = dictonary.map{self.rentalsObject.bond.append(($0.value as? String)!)}
// print(self.arrayOfBond)
case "dateAval" :
_ = dictonary.map{self.rentalsObject.dateAval.append(($0.value as? String)!)}
case "description" :
_ = dictonary.map{self.rentalsObject.descripton.append(($0.value as? String)!)}
case "location" :
_ = dictonary.map{self.rentalsObject.location.append(($0.value as? String)!)}
case "pets" :
_ = dictonary.map{self.rentalsObject.pets.append(($0.value as? String)!)}
case "price" :
_ = dictonary.map{self.rentalsObject.price.append(($0.value as? String)!)}
case "rentalType" :
_ = dictonary.map{self.rentalsObject.rentalType.append(($0.value as? String)!)}
case "title" :
_ = dictonary.map{self.rentalsObject.title.append(($0.value as? String)!)}
print(self.rentalsObject.title)
// _ = dictonary.map{self.arrayOfTitles.append($0.value as? String)}
// print(self.arrayOfTitles)
default:
break
}
}
whateverCollectionIsYourInCacheDataSource = whateverCollectionIsYourInCacheDataSource.sorted(by: { ($0, $1) -> Bool in
return $0 < $1 //If you want to sort them by their date value. Make sure the dates are properly interpreted from whatever format they're saved in remotely into the Date type.
})
DispatchQueue.main.async {
//No need to call .reloadData and these methods in viewDidLoad, unless you REALLY have to (ie: your data is modified on purpose after being loaded initially). Calling these methods loads up the data anyways, so just call these whenever your data is downloaded, converted and sorted properly.
tableView.dataSource = self
tableView.dataSource = self
}
})
}
Hope it helps you on the right path. Look up network-based tableview / collectionview tutorials, they can be very helpful.

Parsing json data through alamofire in table view cells

I am trying to parse json data in my table view cell and its not parsing and not showing the cells . I am attaching all my code please tell me whats the mistake i am doing .. I am not getting any error but the cells are not showing. I have made separate class and functions for json parsing and storing it in an array .
//
// ViewController.swift
// WorkingFeed2
//
// Created by keshu rai on 08/08/17.
// Copyright © 2017 keshu rai. All rights reserved.
//
import UIKit
import Alamofire
import MediaPlayer
class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource{
var post : PostData!
var posts = [PostData]()
typealias DownloadComplete = () -> ()
var arrayOfPostData : [String] = []
#IBOutlet weak var feedTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
feedTable.dataSource = self
feedTable.delegate = self
}
func downloadPostData(completed: #escaping DownloadComplete) {
Alamofire.request("https://new.example.com/api/posts/get_all_posts").responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String,AnyObject> {
if let successcode = dict["STATUS_CODE"] as? Int {
if successcode == 1 {
if let postsArray = dict["posts"] as? [Dictionary<String,AnyObject>]
{
for obj in postsArray
{
let post = PostData(postDict: obj)
self.posts.append(post)
print(obj)
}
// self.posts.remove(at: 0)
self.feedTable.reloadData()
}
}
}
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 419
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : ImageTableViewCell = self.feedTable.dequeueReusableCell(withIdentifier: "contentViewReuse") as! ImageTableViewCell
let post = posts[indexPath.row]
print(post)
cell.configureCell(post : post)
return cell
}
}
This is my PostData Class.
import Foundation
class PostData {
var _profileImageURL : String?
var _fullName : String?
var _location : String?
var _title : String?
var _postTime : String?
var _likes : Int?
var _comments : Int?
var _mediaType : String?
var _contentURL : String?
var _content : String?
var _plocation : String?
var profileImageURL : String
{
if _profileImageURL == nil {
_profileImageURL = ""
}
return _profileImageURL!
}
var fullName : String
{
if _fullName == nil {
_fullName = ""
}
return _fullName!
}
var location : String {
if _location == nil {
_location = ""
}
return _location!
}
var title : String {
if _title == nil {
_title = ""
}
return _title!
}
var postTime : String {
if _postTime == nil {
_postTime = ""
}
return _postTime!
}
var likes : Int {
if _likes == nil {
_likes = 0
}
return _likes!
}
var comments : Int {
if _comments == nil {
_comments = 0
}
return _comments!
}
var mediaType : String {
if _mediaType == nil {
_mediaType = ""
}
return _mediaType!
}
var contentURL : String {
if _contentURL == nil {
_contentURL = ""
}
return _contentURL!
}
var content : String {
if _content == nil {
_content = ""
}
return _content!
}
var pLocation : String {
if _plocation == nil {
_plocation = ""
}
return _plocation!
}
init(postDict : Dictionary<String , AnyObject>)
{
if let postsArray = postDict["posts"] as? [Dictionary<String,AnyObject>]
{
for i in 1..<postsArray.count
{
let fullName1 = postsArray[i]["full_name"] as? String
self._fullName = fullName1
let profileImageURL1 = postsArray[i]["profile_pic"] as? String
self._profileImageURL = profileImageURL1
let location1 = postsArray[i]["user_city"] as? String
self._location = location1
let title1 = postsArray[i]["title"] as? String
self._title = title1
let postTime1 = postsArray[i]["order_by_date"] as? String
self._postTime = postTime1
let likes1 = postsArray[i]["liked_count"] as? Int
self._likes = likes1
let comments1 = postsArray[i]["comment_count"] as? Int
self._comments = comments1
let mediaType1 = postsArray[i]["media_path"] as? String
self._mediaType = mediaType1
let contentURL1 = postsArray[i]["media_path"] as? String
self._contentURL = contentURL1
let content1 = postsArray[i]["content"] as? String
self._content = content1
let plocation1 = postsArray[i]["location"] as? String
self._plocation = plocation1
}
}
}
}
This is my PostDataTableViewCell code.
import UIKit
import Alamofire
class PostDataTableViewCell: UITableViewCell {
#IBOutlet weak var profileImage: UIImageView!
#IBOutlet weak var titlePost: UILabel!
#IBOutlet weak var profileFullName: UILabel!
#IBOutlet weak var profileUserLocation: UILabel!
#IBOutlet weak var likeBtn: UIButton!
var buttonAction: ( () -> Void) = {}
var pressed = false
#IBAction func likeBtnPressed(_ sender: Any) {
if !pressed {
let image = UIImage(named: "Like-1.png") as UIImage!
likeBtn.setImage(image, for: .normal)
pressed = true
} else {
let image = UIImage(named: "liked.png") as UIImage!
likeBtn.transform = CGAffineTransform(scaleX: 0.15, y: 0.15)
UIView.animate(withDuration: 2.0,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 6.0,
options: .allowUserInteraction,
animations: { [weak self] in
self?.likeBtn.transform = .identity
},
completion: nil)
likeBtn.setImage(image, for: .normal)
pressed = false
}
}
#IBAction func commentBtnPressed(_ sender: Any) {
print("Commented")
}
#IBAction func shareBtnPressed(_ sender: Any) {
self.buttonAction()
}
#IBAction func readContentBtnPressed(_ sender: Any) {
print("Read")
}
#IBOutlet weak var contentPostLabel: UILabel!
#IBOutlet weak var contentTypeView: UIView!
#IBOutlet weak var likeAndCommentView: UIView!
#IBOutlet weak var numberOfLikes: UILabel!
#IBOutlet weak var numberOfComments: UILabel!
#IBOutlet weak var postLocation: UILabel!
#IBOutlet weak var postTimeOutlet: UILabel!
func configureCell(post : PostData)
{
titlePost.text = "\(post.title)"
profileFullName.text = "\(post.fullName)"
profileUserLocation.text = "\(post.location)"
numberOfLikes.text = "\(post.likes) Likes"
numberOfComments.text = "\(post.comments) Comments"
postLocation.text = "\(post.pLocation)"
postTimeOutlet.text = "\(post.postTime)"
let url = URL(string: post.profileImageURL)
let data = try? Data(contentsOf: url!)
profileImage.image = UIImage(data: data!)
contentPostLabel.text = "\(post.content)"
if post.mediaType == "image"
{
let url1 = URL(string: post.contentURL)
let data1 = try? Data(contentsOf: url1!)
let image = UIImage(data: data1!)
let imageToView = UIImageView(image: image!)
imageToView.frame = CGRect(x: 0, y: 0, width: 375 , height: 250)
imageToView.contentMode = UIViewContentMode.scaleToFill
contentTypeView.addSubview(imageToView)
}
else if post.mediaType == "null"
{
print("Status")
}
else if post.mediaType == "video"
{
print("Video")
}
else if post.mediaType == "youtube"
{
print("youtube")
}
}
}
Most likely the issue occurs because you are trying to parse the value for key posts twice, once in PostData and once in ViewController.
First of all in Swift 3 a JSON dictionary is [String:Any], secondly – as already mentioned in my comment – private backing variables are nonsense in Swift.
The class PostData can be reduced to
class PostData {
let profileImageURL : String
let fullName : String
let location : String
let title : String
let postTime : String
let likes : Int
let comments : Int
let mediaType : String
let contentURL : String
let content : String
let plocation : String
init(postDict : [String:Any])
{
fullName = postDict["full_name"] as? String ?? ""
profileImageURL = postDict["profile_pic"] as? String ?? ""
location = postDict["user_city"] as? String ?? ""
title = postDict["title"] as? String ?? ""
postTime = postDict["order_by_date"] as? String ?? ""
likes = postDict["liked_count"] as? Int ?? 0
comments = postDict["comment_count"] as? Int ?? 0
mediaType = postDict["media_path"] as? String ?? ""
contentURL = postDict["media_path"] as? String ?? ""
content = postDict["content"] as? String ?? ""
plocation = postDict["location"] as? String ?? ""
}
}

Send array by segue to new view controller swift iOS 9

I am attempting to send an array of data to a new view controller and I'm currently getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
Im using the API data from www.thecocktaildb.com
Example:
http://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita
Not sure what I'm doing wrong. Tried debugging and checking values before the segue in my search view controller and they're accurate.
Heres my code:
Main Storyboard
SearchViewController
class SearchViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
#IBOutlet weak var SearchBar: UISearchBar!
var valueToPass:Drinks!
var isSearching : Bool = false
class Drinks {
var idDrink: Int = 0
var strDrink: String = ""
var strCategory: String = ""
var strAlcoholic: String = ""
var strGlass: String = ""
var strInstructions: String = ""
var strDrinkThumb: String = ""
var strIngredient1: String = ""
var strIngredient2: String = ""
var strIngredient3: String = ""
var strIngredient4: String = ""
var strIngredient5: String = ""
var strIngredient6: String = ""
var strIngredient7: String = ""
var strIngredient8: String = ""
var strIngredient9: String = ""
var strIngredient10: String = ""
var strIngredient11: String = ""
var strIngredient12: String = ""
var strIngredient13: String = ""
var strIngredient14: String = ""
var strIngredient15: String = ""
var strMeasure1: String = ""
var strMeasure2: String = ""
var strMeasure3: String = ""
var strMeasure4: String = ""
var strMeasure5: String = ""
var strMeasure6: String = ""
var strMeasure7: String = ""
var strMeasure8: String = ""
var strMeasure9: String = ""
var strMeasure10: String = ""
var strMeasure11: String = ""
var strMeasure12: String = ""
var strMeasure13: String = ""
var strMeasure14: String = ""
var strMeasure15: String = ""
}
var TableData:Array< Drinks > = Array < Drinks >()
override func viewDidLoad() {
super.viewDidLoad()
for subView in self.SearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""))
}
}
}
self.SearchBar.delegate = self
self.TableView.delegate = self
self.TableView.dataSource = self
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if self.SearchBar.text!.isEmpty {
self.isSearching = false
}else{
self.isSearching = true
let userSearchInput = self.SearchBar.text!.lowercaseString
let newString = userSearchInput.stringByReplacingOccurrencesOfString(" ", withString: "%20", options: NSStringCompareOptions.LiteralSearch, range: nil)
let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/search.php?s=" + newString
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling GET on www.thecocktaildb.com")
print(error)
return
}
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
}
var count = 1
if let drinks = post["drinks"] as? [NSDictionary] {
self.TableData.removeAll()
for drink in drinks {
let adrink = Drinks()
if let strDrink = drink["strDrink"] as? String {
print(String(count) + ". " + strDrink)
adrink.strDrink = strDrink
count++
}
if let strCategory = drink["strCategory"] as? String {
print(" Category: " + strCategory)
adrink.strCategory = strCategory
}
if let strDrinkThumb = drink["strDrinkThumb"] as? String {
print(" Thumbnail Image: " + strDrinkThumb)
adrink.strDrinkThumb = strDrinkThumb
}
self.TableData.append(adrink)
self.TableView.reloadData()
}
}
})
task.resume()
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
//title = TableData[indexPath.row].strDrink
cell.textLabel?.text = TableData[indexPath.row].strDrink;
let imageString = TableData[indexPath.row].strDrinkThumb
if (imageString == ""){
let noDrinkImage : UIImage = UIImage(named: "noimage.jpg")!
cell.imageView!.image = noDrinkImage
}else{
let drinkImage = UIImage(data: NSData(contentsOfURL: NSURL(string:TableData[indexPath.row].strDrinkThumb)!)!)
cell.imageView!.image = drinkImage
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
print(TableData[indexPath.row].strDrink)
valueToPass = TableData[indexPath.row]
//self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
}
// hide kwyboard when search button clicked
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
self.SearchBar.resignFirstResponder()
}
// hide keyboard when cancel button clicked
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.SearchBar.text = ""
self.SearchBar.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
}
}
}
DrinkViewController.swift
class DrinkViewController: UIViewController {
#IBOutlet weak var DrinkNameLabel: UILabel!
var passedValue : SearchViewController.Drinks!
override func viewDidLoad() {
super.viewDidLoad()
DrinkNameLabel.text = passedValue!.strDrink
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Do it like this instead
In your didSelectRowAtIndexPath pass the array
self.performSegueWithIdentifier("drinkSegue", sender: TableData[indexPath.row])
Here you need to pass the array to your DrinkViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DrinkSegue") {
// initialize new view controller and cast it as your view controller
let drinkViewController = segue.destinationViewController as! DrinkViewController
// your new view controller should have property that will store passed value
drinkViewController.passedValue = valueToPass
// declare myArray in your drinkViewController and then assign it here
// now your array that you passed will be available through myArray
drinkViewController.myArray = sender
}
}
Update
After I got your project I noticed that the issue you had was that you did drag a segue from the tableView to the drinksController directly - what happened is that didSelectRowAtIndexPath will not be called and your sender will always be nil drinkViewController.myArray = sender as! Drinks.
I changed that by dragging the segue from the viewController to the drinksController instead.

Resources