Why tableviewcell is returning an optional("") - ios

I am trying to display the result of my request from an api into a cell.I am able to make the request and parse the data. But when I try to display the content in a cell and print the cell value, the result is optional (“”).Can someone explain me why .
cell.restaurantNameLabel.text = apiDataModel.restaurantName
apiDataModel.restaurantName is not nil
Any help is appreciated ! Thanks
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DiscoverTableViewCell
cell.discoverImage.image = UIImage(named: "Detail")
cell.restaurantNameLabel.text = apiDataModel.restaurantName
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentCell = tableView.cellForRow(at: indexPath) as! DiscoverTableViewCell
print(currentCell.restaurantNameLabel.text)
}
func search(url: String, parameters : [String:String]) {
let headers: HTTPHeaders = ["Authorization":"Bearer \(apiKey)"]
Alamofire.request(url, method: .get, parameters: parameters, headers: headers ) .responseJSON{
URLResponse in
//print(URLResponse)
if URLResponse.result.isSuccess {
let yelpDataJSON = JSON(URLResponse.value!)
self.updateYelpData(Json: yelpDataJSON)
print("\(yelpDataJSON)")
}else{
print("error")
}
}
}
func updateYelpData(Json : JSON){
if let nameJSON = Json["businesses"][0]["name"].string {
apiDataModel.restaurantName = nameJSON
print(apiDataModel.restaurantName)
apiDataModel.restaurantLocation = Json["businesses"][0]["location"]["display_address"][0].stringValue
}else{
print("error")
}
}

You’re not showing us where you called search, but request is an asynchronous method, but you never call reloadData on your table view inside updateYelpData. Thus the initial population of the table view is happening before the data has been retrieved and parsed by Alamofire.
If you put a tableView.reloadData() inside updateYelpData, the table view will be update with real data after it is retrieved by Alamofire.

It appears apiDataModel.restaurantName is nil / "" and setting that to the label text will make it ""
You need to reload the table after
self.updateYelpData(Json: yelpDataJSON)
self.tableView.reloadData()
and make sure you have a valid result

Related

JSON response not being shown inside the cell

I’m creating a Tableview and trying to include in the cell one information that I receive through a JSON from an API.
The information (JSON) is being received very well and recorded correctly inside the variable.
However, what I could find is that as the information is received with a small “delay” is not being set as the cell’s label text at the cell creation moment, which is being set with the default variable content.
I guess the solution would be to update the label at the moment I parse the JSON content, right? How do I do this? (Update a cell’s label after it is already created)
Any other insight/ solution is greatly appreciated.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, AddStock {
let operacoesAcoes = ListaOperacoes()
var todasAsOperacoes : [Operacao] = []
#IBOutlet weak var acoesTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
acoesTableView.delegate = self
acoesTableView.dataSource = self
acoesTableView.register(UINib(nibName: "StandardStockListCell", bundle: nil), forCellReuseIdentifier: "standardCell")
operacoesAcoes.consolidaAcoes()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return operacoesAcoes.carteiraAcoes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "standardCell", for: indexPath) as! StandardStockListCell
let informacaoCompletaAcao = operacoesAcoes.carteiraAcoes[indexPath.row]
cell.codigoTextField.text = informacaoCompletaAcao.codigoAcao
cell.nomeTextField.text = informacaoCompletaAcao.nomeAcao
cell.quantidadeTotal.text = String(informacaoCompletaAcao.quantidadeTotal)
cell.precoMedioLabel.text = String(format: "%.2f", informacaoCompletaAcao.precoMedio)
//
// This is the part of the code that should set one label with a value returned from "buscaCotacao" but it does not work
// because at the time the cell is displayed it is still not updated from JSON information:
// Note: the buscaCotacao func is working fine
cell.precoAtualLabel.text = buscaCotacao(ativo: informacaoCompletaAcao.codigoAcao)
return cell
}
You need to reload the table view on the main thread after receiving and parsing the JSON.
self.acoesTableView.reloadData()
I did some research and tryouts, and could figure out a very simple (and now obvious) solution to update my Label after the result of the request is received:
- I call the function which retrieves the information from an API to update the cell ("buscaCotacao"), including the [cell row] information
- I update the cell's label from inside the function, which will happen only after the reply is received:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "standardCell", for: indexPath) as! StandardStockListCell
let informacaoCompletaAcao = operacoesAcoes.carteiraAcoes[indexPath.row]
cell.codigoTextField.text = informacaoCompletaAcao.codigoAcao
cell.nomeTextField.text = informacaoCompletaAcao.nomeAcao
cell.quantidadeTotal.text = String(informacaoCompletaAcao.quantidadeTotal)
cell.precoMedioLabel.text = "R$ "+String(format: "%.2f", informacaoCompletaAcao.precoMedio)
buscaCotacao(ativo: informacaoCompletaAcao.codigoAcao, for: cell, indexPath: indexPath)
return cell
}
And in the function:
func buscaCotacao (ativo: String, for cell: StandardStockListCell, indexPath: IndexPath) {
let finalURL = "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&interval=1min&apikey=XXXXXXXXXXXXXX&outputsize=compact&symbol=" + ativo
Alamofire.request(finalURL, method: .get)
.responseJSON { response in
if response.result.isSuccess {
let resultadoJSON : JSON = JSON(response.result.value!)
let resultado = Float (self.parseResultado(json: resultadoJSON))!
cell.precoAtualLabel.text = "R$ "+String(format: "%.2f", resultado)
self.cotacoes[ativo] = resultado
} else {
cell.precoAtualLabel.text = "N/D"
print("Error: \(response.result.error!)")
}
}
}

iOS - Wait for a query to be completed

I have a table that displays the results of an http request.
Sometimes the application crashes because the table is displayed before the query is finished .. How can the application no crash?
The table :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MyCustomCell
for i in 0...nameOfRoutesStart.count {
if (indexPath.row == i) {
cell.originLabel.text = nameOfRoutesStart[i]
cell.destinationLabel.text = nameOfRoutesEnd[i]
let id = driver[i]
self.userTasks.user(driverId: id, completionHandler: { (status, success) -> Void in
if success {
cell.driverLabel.text = self.userTasks.username
}
})
cell.textLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
}
}
return cell
}
I make the request in another function
Thanks
Extract your asynchronous code from the tableview methods to your viewDidLoad. Save the data you retrieve in a variable declared in your controller and call .reloadData() on your tableview when your fetch is finished.

Image repeates in every cell of table view in swift3

My JsonData -
let imagestring : String? = (myData as AnyObject).value(forKey: "Post_mid_image") as? String
if imagestring != nil {
let imageTrueString = "https://www.zdoof.com/" + imagestring!
self.imageStringArray.append(imageTrueString )
}
if let NameString = (myData as AnyObject).value(forKey: "Name") as? String {
self.nameStringArray.append(NameString)
}
When i am trying to set it to the table view cell
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.postLableArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reUse", for: indexPath)
let myImage = cell.viewWithTag(30) as! UIImageView
myImage.clipsToBounds = true
if indexPath.row < imageStringArray.count {
if let myImageString = imageStringArray[indexPath.row] as? String {
let ImageUrl = URL.init(string: myImageString)
myImage.kf.setImage(with: ImageUrl)
}
}
return cell
}
The image is repeating in every cell . Why it is happening ? Please help
As per the response you have given, you can show the image like below:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let dict = myData as AnyObject
let cell = tableView.dequeueReusableCell(withIdentifier: "reUse", for: indexPath)
let myImage = cell.viewWithTag(30) as! UIImageView
if dict["Post_mid_image"] != nil {
let imageUrl = URL.init(string: strImageUrl)
myImage.kf.setImage(with: imageUrl)
} else {
//Set placeholder image showing no image available
}
return cell
}
Problem is with cell re-usablity of table view here ,you have to handle it , you can have SDWebImage library for loading images in cell or you can have your own image cache which caches images with key/values , key as in image url , so dynamically checking image url for item at indexpath and load cached image with that image url as key.
Hope it helps!!
This is happening because of using tableView.dequeueReusableCell(withIdentifier: "reUse", for: indexPath).
Basically whenever you use dequeueReusableCell(withIdentifier:,For:), it will use the same cell for all of data. It means the total number of cell which are on screen are only going to load, for all other cell, it will use same cell with different value.
now consider a scenario that you are having 500 cells in tableview, but we can manage at most 10-15 cells in display, so for all other cells it will use same cells just modify the value of cell.
so what you can do here is, whenever you use if statement, don't forgot to add else too.
because for one scenario if cell's background is set to red, than we need to add else for another scenario, as cells are just repeated.

Loading image from URL is working inconsistently

I am storing URLs as Strings in an Organization. These URLs are used to fetch each Organization's logo and display it in a tableview. Here is the code I am using to do this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "orgcell", for: indexPath) as! OrgCell
cell.orgAcro.text = filteredOrgs[indexPath.row].acronym
cell.topTag.text = filteredOrgs[indexPath.row].tags[0].title
let data = try? Data(contentsOf: filteredOrgs[indexPath.row].url)
if (data == nil) {
cell.orgImg.image = UIImage()
} else {
cell.orgImg.image = UIImage(data: data!)
}
return cell
}
The only URL this is working for is this one https://pbs.twimg.com/profile_images/718076464856338432/zlcMj0Oo.jpg
It is not working for this one http://www.therightfew.com/wp-content/uploads/2016/09/Planned-Parenthood-Logo-Square.jpg
It has nothing to do with the order by which I load them, I have tried switching it up. Any ideas as to what's going on?

Error when creating tableview with multiple custom cells

I have encountered an error in swift when attempting to create a tableview made up of custom cells dependent upon a set of conditions.
Here is my code:
var tableData: [String] = []
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// number of rows in table view
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableData.count
}
// create a cell for each table view row
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let phonenocell:MyCustomCell = self.tableView.dequeueReusableCellWithIdentifier("phonecell", forIndexPath: indexPath) as! MyCustomCell
let pincell:SocialCell = self.tableView.dequeueReusableCellWithIdentifier("socialcell", forIndexPath: indexPath) as! SocialCell
let fbcell:FacebookCell = self.tableView.dequeueReusableCellWithIdentifier("facebookcell", forIndexPath: indexPath) as! FacebookCell
let snapcell:SnapchatCell = self.tableView.dequeueReusableCellWithIdentifier("snapchatcell", forIndexPath: indexPath) as! SnapchatCell
let twitcell:TwitterCell = self.tableView.dequeueReusableCellWithIdentifier("twittercell", forIndexPath: indexPath) as! TwitterCell
let instacell:InstagramCell = self.tableView.dequeueReusableCellWithIdentifier("instagramcell", forIndexPath: indexPath) as! InstagramCell
if tableData.contains("Number") {
return phonenocell
}
if tableData.contains("Social") {
return pincell
}
if tableData.contains("Facebook") {
return fbcell
}
if tableData.contains("Snapchat") {
return snapcell
}
if tableData.contains("Twitter") {
return twitcell
}
if tableData.contains("Instagram") {
return instacell
}
}
When attempting to build and run I get a build failed with the following fault:
"Missing Return in a function expected to return 'UITableViewCell'
I have been over and over my code but I honestly cannot see where I am going wrong...
Any help would be greatly appreciated!
You need to return cell for sure.
You already do in conditions, but in case none of your condition statements would success, your return call wouldn't be fired.
Appending, for example:
return phonenocell
to the end of the function, should be quick fix for your code. It ensures, that the function will return a cell (that is mandatory).
My data source is the array tableData. This is constructed on the previous view as: #IBAction func switch1Toggled(sender: UISwitch) { if mySwitch1.on { fbTextBox.text = "Selected" dataArray.append("Facebook")
And this may be the main issue:
Assuming, that you choose 'facebook' and that you reload your tableView, every row will pass the first condition as it IS contained.
You should put this in your method:
//assuming your data source contains multiple members, and your numberOfRowsInSections... method return tableData.count, you need to get each item for each row:
let currentTag = tableData[indexPath.row]
if (currentTag == "something") { //e.g. Facebook
let somethingcell:MySomethingCell = ...
self.tableView.dequeueReusableCellWithIdentifier("somethingcell", forIndexPath: indexPath) as! MySomethingCell
return somethingcell
} else if {
...
}
return emptycell //this line is just for the case, when no of your conditions will pass and you don't catch all the situations...
maybe your array elements doesn't match the condition, it's better to return default value instead of ur conditions failed

Resources