Cell in TableView not displaying info. Swift - swift

Cell not displaying anything, but print(dictionary) is displaying correct info. So I am getting the correct information
Here is my code:
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseAnalytics
class VCTableViewController: UITableViewController {
var ref: DatabaseReference!
var refHandle: UInt!
var requestList = [request]()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
ref = Database.database().reference()
fetchUsers()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for:indexPath)
// let cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellId)
cell.textLabel?.text = requestList[indexPath.row].name
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return requestList.count
}
func fetchUsers() {
refHandle = ref.child("Request").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String : AnyObject] {
print(dictionary)
let request1 = request(dictionary: dictionary)
// request1.setValuesForKeys(dictionary)
self.requestList.append(request1)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
}
}
My request swift file:
import Foundation
class request: NSObject {
var request: String?
var name: String?
var longitude: String?
var latitude: String?
init (dictionary: [String: Any]) {
super.init()
request = dictionary["request"] as? String
}
}

Try this:
class request: NSObject {
var request: String?
var name: String?
var longitude: String?
var latitude: String?
init (dictionary: [String: Any]) {
super.init()
name = dictionary["name"] as? String
longitude = dictionary["longitude"] as? String
latitude = dictionary["latitude"] as? String
}
}
But there are better ways to deserialize. Take a look at Codable.
Here's an example that gives you something to think about going forward:
//Codable protocol is for both Encoding & Decoding
struct Location: Codable {
let name: String
let longitude: String
let latitude: String
}
//Encode to json format from struct
let location = Location(name: "my location", longitude: "-94.420307", latitude: "44.968046")
if let encoded = try? JSONEncoder().encode(location) {
if let encodedJSON = String(data: encoded, encoding: .utf8) {
print(encodedJSON)
//Prints: {"name":"my location","longitude":"-94.420307","latitude":"44.968046"}
}
}
//Decode from json data to struct
let jsonStr = """
{
\"name\": \"my location\",
\"longitude\": \"-94.420307\",
\"latitude\": \"44.968046\"
}
"""
//jsonData is of type Data? which is generally what comes back from http request.
if let jsonData = jsonStr.data(using: .utf8) {
if let decoded = try? JSONDecoder().decode(Location.self, from: jsonData) {
print(decoded.name, decoded.longitude, decoded.latitude)
//Prints: "my location -94.420307 44.968046"
}
}

Related

Reloading cells in view after image downloaded

I am currently learning swift. I have experience in android but now time for something new. I am starting with basics to load movie DB from API to table. I am storing dowloaded poster in Movie class (which also downloads them) when scrolling I can see the posters but after download the current cells in the view not updated, only after scroll. How can I implement callback from Movie to table view to update visible cells after download.
Movie:
import UIKit
let URL_PREFIX = "https://image.tmdb.org/t/p/original"
class Movie {
let movieId: CLong?
let title: String?
let posterPath: String?
let overview: String?
let releaseDate: String?
var posterImage: UIImage?
var callback: ((_ id: Int) -> Void)?
init(movieId: CLong,title: String,posterPath: String,overview: String,releaseDate: String,posterImage: UIImage?=nil) {
self.movieId = movieId
self.title = title
self.posterPath = posterPath
self.overview = overview
self.releaseDate = releaseDate
self.posterImage = posterImage
setResizedImage(path: posterPath)
}
func setResizedImage(path: String)
{
let conPath = URL_PREFIX + path
print("Path: \(conPath)")
guard let urlPath = URL(string: conPath) else {
print("You fucked up")
return
}
print("Download Started")
getData(from: urlPath) { data, response, error in
guard let _ = data, error == nil else { return }
print(response?.suggestedFilename ?? urlPath.lastPathComponent)
print("Download Finished")
//update
DispatchQueue.main.async()
{
self.posterImage = UIImage(data: data!)
}
}
}
}
MyViewController:
import UIKit
let URL_MOVIES = "https://api.themoviedb.org/3/movie/upcoming?
api_key=000";
class DataViewController: UIViewController,UITableViewDelegate,
UITableViewDataSource {
#IBOutlet weak var myTable: UITableView!
var movieArray :[Movie] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movieArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MovieTableViewCell", for: indexPath) as? CustomTableViewCell else {
fatalError("The dequeued cell is not an instance of MovieTableViewCell.")
}
let movie = movieArray[indexPath.row]
cell.title.text = movie.title
cell.releaseDate.text = movie.releaseDate
cell.overview.text = movie.overview
//cell.url.text = movie.overview
if (movie.posterImage==nil)
{
print("Loaded placeholder")
cell.poster.image = UIImage(named: "poster")
}
else
{
print("Hello2")
cell.poster.image = movie.posterImage
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped cell number \(indexPath.row).")
}
override func viewDidLoad() {
super.viewDidLoad()
myTable.rowHeight = UITableView.automaticDimension
myTable.estimatedRowHeight = 50
getJsonFromUrl()
}
func getJsonFromUrl(){
let url = NSURL(string: URL_MOVIES)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
if let resultArray = jsonObj.value(forKey: "results") as? NSArray
{
for film in resultArray
{
if let movieDict = film as? NSDictionary
{
//getting the name from the dictionary
let id = movieDict.value(forKey: "id")
let title = movieDict.value(forKey: "title")
let posterPath = movieDict.value(forKey: "poster_path")
let overview = movieDict.value(forKey: "overview")
let releaseDate = movieDict.value(forKey: "release_date")
let movie = Movie(movieId:id as! CLong, title: title as! String, posterPath: posterPath as! String, overview: overview as! String, releaseDate: releaseDate as! String)
self.movieArray.append(movie)
}
}
}
OperationQueue.main.addOperation({
self.myTable.reloadData()
})
}
}).resume()
}
}
You can add the download function inside the cell custom class and assign the imageView inside the callback, but this has many problems such as redownloading same image multiple times when scrolling, it's better to use SDWebImage or you can use Kingfisher Library
import SDWebImage
cell.poster.sd_setImage(with: URL(string:movie.imageUrlStr), placeholderImage: UIImage(named: "placeholder.png"))

Search Bar Swift 3 - Can't use in/contains operator with collection

I am implementing a search bar into my project but I am being presented with the below error.
reason: 'Can't use in/contains operator with collection wellpleased.attendees.UserData(firstname: "Ben", lastname: "Delonge", fullname: "Ben Delonge", company: "AllStar.com", jobtitle: "Business Development Manager", image: "6.jpg") (not a collection)'
I have done plenty of searching around the NSPredicate but cannot seem to prevent this crashing.
I am using the code below, any assistance resolving this would be much appreciated.
class attendees: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var tableData = ""
var value:String!
var searchString: String = ""
var dataSource: [UserData] = []
struct UserData {
var firstname: String
var lastname: String
var fullname: String
var company: String
var jobtitle: String
var image: String
}
var filteredAppleProducts = [String]()
var resultSearchController = UISearchController()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
print(value)
searchBar.delegate = self
self.tableView.reloadData()
let nib = UINib(nibName: "vwTblCell2", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell2")
}
override func viewDidAppear(_ animated: Bool) {
getTableData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if filteredAppleProducts != []{
return self.filteredAppleProducts.count
}
else
{
if searchString != "[]" {
return self.dataSource.count
}else {
return 0
}
}
}
// 3
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell2: TblCell2 = self.tableView.dequeueReusableCell(withIdentifier: "cell2") as! TblCell2
print(filteredAppleProducts)
if filteredAppleProducts != []{
cell2.nameLabel.text = self.filteredAppleProducts[indexPath.row]
return cell2
}
else
{
if searchString != "[]"{
cell2.nameLabel.text = self.dataSource[indexPath.row].fullname
cell2.companyLabel.text = self.dataSource[indexPath.row].company
cell2.jobTitleLabel.text = self.dataSource[indexPath.row].jobtitle
let url = URL(string: "https://www.asmserver.co.uk/wellpleased/backend/profileimages/\(self.dataSource[indexPath.row].image)")
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell2.userImage.image = UIImage(data: data!)
}
return cell2
}
}
// 4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
// 5
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
func updateSearchResults(){
self.filteredAppleProducts.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchString)
let array = (self.dataSource as NSArray).filtered(using: searchPredicate)
self.filteredAppleProducts = array as! [String]
self.tableView.reloadData()
print(filteredAppleProducts)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print("searchText \(searchText)")
print(filteredAppleProducts)
searchString = searchText
updateSearchResults()
}
func getTableData(){
self.dataSource.removeAll()
let defaults = UserDefaults()
let userid = defaults.string(forKey: "id")
let url = NSURL(string: "https://www.******.co.uk/wellpleased/backend/searchattendees.php?userid=\(userid!)&eventid=\(value!)")
print(url)
let task = URLSession.shared.dataTask(with: url as! URL) { (data, response, error) -> Void in
if let urlContent = data {
do {
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [[String:AnyObject]] {
var i = 0
while i < jsonResult.count {
self.dataSource.append(UserData(firstname:"\(jsonResult[i]["firstname"]! as! String)", lastname: "\(jsonResult[i]["lastname"]! as! String)", fullname:"\(jsonResult[i]["fullname"]! as! String)", company: "\(jsonResult[i]["company"]! as! String)", jobtitle:"\(jsonResult[i]["jobtitle"]! as! String)", image:"\(jsonResult[i]["image"]! as! String)"))
i = i + 1
}
}
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
self.tableView.isUserInteractionEnabled = true
}
task.resume()
}
}
I have also tired:
let searchPredicate = NSPredicate(format: "fullname CONTAINS[c] %#", searchString as String)
which returns the error:
this class is not key value coding-compliant for the key fullname
NSPredicate is a Cocoa feature that lives in the Objective-C world. It's never going to work on an array of UserData because UserData is a Swift struct — and Objective-C cannot see a Swift struct at all (and even if it could, it certainly can't see any type namespaced inside a class, as your UserData is).
You would have an easy time of this if you simply used the built-in Swift filter method to filter the dataSource array. For example (if this is what you're trying to do):
let array = self.dataSource.filter{$0.fullname.contains(searchString)}
In Swift 3, you can combine NSArray with NSPredicate like this:
let searchPredicate = NSPredicate(format: "%K CONTAINS[c] %#", "fullname",searchString)
let array = NSArray(array: self.dataSource).filtered(using: searchPredicate)

Swift 3 table search

I have populated a table using json data from a remote server.
I am now trying to add a search bar which will filter the results.
The issue I am facing is that I am storing the json data in several arrays.
name, company, job title etc
This means that when the user searches only the name array is filtered and displayed in the table correctly, the other information is out of sync as it remains unfiltered.
Am I approaching this in the correct way?
class attendees: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var tableData = ""
var value:String!
var searchString = ""
var firstname: [String] = []
var lastname: [String] = []
var fullname: [String] = []
var company: [String] = []
var jobtitle: [String] = []
var image: [String] = []
var filteredAppleProducts = [String]()
var resultSearchController = UISearchController()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
print(value)
searchBar.delegate = self
self.tableView.reloadData()
let nib = UINib(nibName: "vwTblCell2", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell2")
}
override func viewDidAppear(_ animated: Bool) {
getTableData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if filteredAppleProducts != []{
return self.filteredAppleProducts.count
}
else
{
if searchString != "[]" {
return self.firstname.count
}else {
return 0
}
}
}
// 3
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell2: TblCell2 = self.tableView.dequeueReusableCell(withIdentifier: "cell2") as! TblCell2
print(filteredAppleProducts)
if filteredAppleProducts != []{
cell2.nameLabel.text = self.filteredAppleProducts[indexPath.row]
return cell2
}
else
{
if searchString != "[]"{
cell2.nameLabel.text = "\(self.firstname[indexPath.row]) \(self.lastname[indexPath.row])"
cell2.companyLabel.text = self.company[indexPath.row]
cell2.jobTitleLabel.text = self.jobtitle[indexPath.row]
let url = URL(string: "https://www.asmserver.co.uk/wellpleased/backend/profileimages/\(self.image[indexPath.row])")
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell2.userImage.image = UIImage(data: data!)
}
return cell2
}
}
// 4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
// 5
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90
}
func updateSearchResults(){
self.filteredAppleProducts.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchString)
let array = (self.fullname as NSArray).filtered(using: searchPredicate)
self.filteredAppleProducts = array as! [String]
self.tableView.reloadData()
print(filteredAppleProducts)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print("searchText \(searchText)")
print(filteredAppleProducts)
searchString = searchText
updateSearchResults()
}
func getTableData(){
self.firstname.removeAll()
self.lastname.removeAll()
self.fullname.removeAll()
self.company.removeAll()
self.jobtitle.removeAll()
self.image.removeAll()
let defaults = UserDefaults()
let userid = defaults.string(forKey: "id")
let url = NSURL(string: "https://www.asmserver.co.uk/wellpleased/backend/searchattendees.php?userid=\(userid!)&eventid=\(value!)")
print(url)
let task = URLSession.shared.dataTask(with: url as! URL) { (data, response, error) -> Void in
if let urlContent = data {
do {
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [[String:AnyObject]] {
var i = 0
while i < jsonResult.count {
self.firstname.append(jsonResult[i]["firstname"]! as! String)
self.lastname.append(jsonResult[i]["lastname"]! as! String)
let fname = jsonResult[i]["firstname"]! as! String
let lname = jsonResult[i]["lastname"]! as! String
let fullname1 = "\(fname) \(lname)"
self.fullname.append(fullname1)
self.company.append(jsonResult[i]["company"]! as! String)
self.jobtitle.append(jsonResult[i]["jobtitle"]! as! String)
self.image.append(jsonResult[i]["image"]! as! String)
i = i + 1
}
}
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
self.tableView.isUserInteractionEnabled = true
}
task.resume()
}
}
Use a struct or class for the data. This way it'll be easier to keep track of the data, and in any case it looks like you don't have any good reason to keep track of seven different arrays.
As an example:
struct Data {
var firstName: String
var lastName: String
var fullName: String
var company: String
var jobTitle: String
var image: String
}
And populate just the one array:
var dataSource: [Data] = []
Access with property name, instead of arrayName[index]:
let name = dataSource[index].firstName

Swift 3 Custom TableViewCell Error

I am having trouble communicating with the "TableView". How can I solve the problem?
Error Image
Code Image
var arrayOfData = [cellData]()
var fullname1 : String!
var code1 : String!
var name1 : String!
var buy1 : Double!
var sell1 : Double!
var change_rate1 : Double!
var update_date1 : Double!
var arrayFullName : [String] = ["asdas","asds","asds","sadas","asdasd","asdas"]
#IBOutlet weak var tblDoviz: UITableView!
#IBOutlet weak var openBarButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
arrayOfData = [cellData(fullName: "Amerikan Doları", name: "", code: "USD", updateDate: 2, changeRate: 2, buy: 3.44, sell: 3.47)]
openBarButton.target = self.revealViewController()
openBarButton.action = Selector("revealToggle:")
tblDoviz.delegate = self
tblDoviz.dataSource = self
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
/* Doviz Sitesinden Bilgiler Çekiliyor */
let url = NSURL(string: "http://www.doviz.com/api/v1/currencies/all/latest")
let task = URLSession.shared.dataTask(with: url as! URL){(data,response,error) ->Void in
if error != nil
{
}
else
{
if let urlContent = data
{
do
{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if let currencyRate = jsonResult as? NSArray
{
for i in 0..<currencyRate.count
{
if let name = (currencyRate[i] as? NSDictionary)?["name"] as? String
{
self.name1 = name
}
if let fullname = (currencyRate[i] as? NSDictionary)?["full_name"] as? String
{
self.fullname1 = fullname
}
if let change_rate = (currencyRate[i] as? NSDictionary)?["change_rate"] as? Double
{
self.change_rate1 = change_rate
}
if let code = (currencyRate[i] as? NSDictionary)?["code"] as? String
{
self.code1 = code
}
if let update_date = (currencyRate[i] as? NSDictionary)?["update_date"] as? Double
{
self.update_date1 = update_date
}
if let buying = (currencyRate[i] as? NSDictionary)?["buying"] as? Double
{
self.buy1 = buying
}
if let selling = (currencyRate[i] as? NSDictionary)?["selling"] as? Double
{
self.sell1 = selling
}
//Array'a Yükleme Yapılıyor
//cellData.init(fullName: self.fullname1, name: self.name1, code: self.code1, updateDate: self.update_date1, changeRate: self.change_rate1, buy: self.buy1, sell: self.sell1)
//self.arrayOfData = [cellData(fullName: self.fullname1, name: self.name1, code : self.code1, updateDate: self.update_date1, changeRate: self.change_rate1, buy: self.buy1, sell: self.sell1)]
//print(self.arrayOfData)
//print(cellData())
}
print(self.arrayFullName.count)
}
}
catch
{
}
}
}
}
task.resume()
//--------------------------------------------------
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDoviz",for:indexPath) as! DovizCell1
Error-------------------------------------
cell.lblText.text = arrayFullName[indexPath.row]
Error -----------------------------------
return cell as DovizCell1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 94
}
}
Try adding this to your code
let cell:DovizCell? = tableView.dequeueReusableCell(withIdentifier: "cellDoviz",for:indexPath) as! DovizCell
if cell == nil {
cell = NSBundle.mainBundle().loadNibNamed("DovizCell").first as! DovizCell
}
Your DovizCell might have been nil which is why the code crashed

Swift: Retrieve data from Firebase Database to label

I'm trying to get my data from Firebase Database to particular label in Swift. I have two labels in TableView (as Main.storyboard) tagged 1 and 2.
In a ViewController, I have this code:
import UIKit
import Firebase
import FirebaseDatabase
struct confStruct {
let title : String!
let place : String!
}
class EVS_Table_VC: UITableViewController {
var conf = [confStruct]()
override func viewDidLoad() {
super.viewDidLoad()
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("conferences").queryOrderedByKey().observeEventType(.ChildAdded, withBlock: {
snapshot in
self.tableView.reloadData()
})
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return conf.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = conf[indexPath.row].title
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = conf[indexPath.row].place
return cell!
}
}
But nothing shows up in a Simulator. Does somebody have a proposition how to resolve this? This struct confStruct initializes my variable from
Database? (title, place).
JSON tree:
"conferences": {
"Key": {
"date": "some date"
"deadline": "some deadline"
"place": "some place"
"title": "some title"
}
}
Change your struct to :-
struct confStruct {
let title : String!
let place : String!
init(title_String : String!, place_String : String!){
self.title = title_String
self.place = place_String
}
}
And:-
FIRDatabase.database().reference().child("conferences/Key").observeSingleEvent(of: .value, with: {(snap) in
if let snapDict = snap.value as? [String:AnyObject]{
let titleS = snapDict["title"] as! String
let placeS = snapDict["place"] as! String
let temp = confStruct.init(title_String: titleS, place_String: placeS)
self. conf.append(temp)
self.tableView.reloadData()
}
})