Different cells in tableview swift 3 - ios

example [1]: https://i.stack.imgur.com/8cORc.png
how to make the following table correctly
I do not want crutches
All cells one by one, except for a block of X.count, there will be a different number (from two or more)
how to find out the first and last cells from Block X later to show or hide the strip between the cells (between the points, I make their three thin ones, and want to hide or show the cell depending on the cell)
import UIKit
import CoreLocation
import Alamofire
import SwiftyJSON
class TableVC: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var loadingView: UIView!
var number: String! = "number"
var detail_data: DetailListData?
var token: String?
var json = "Invalid"
override func viewDidLoad() {
super.viewDidLoad()
loadingView.isHidden = false
print("===============================",number!)
tableView.register(UINib(nibName: "HeaderTVC", bundle: Bundle.main), forCellReuseIdentifier: "HeaderTVC")
tableView.register(UINib(nibName: "DistanceTVC", bundle: Bundle.main), forCellReuseIdentifier: "DistanceTVC")
tableView.register(UINib(nibName: "MapTVC", bundle: Bundle.main), forCellReuseIdentifier: "MapTVC")
tableView.register(UINib(nibName: "InfoTVC", bundle: Bundle.main), forCellReuseIdentifier: "InfoTVC")
tableView.register(UINib(nibName: "BottomTVC", bundle: Bundle.main), forCellReuseIdentifier: "BottomTVC")
tableView.delegate = self
token = UserDefaults.standard.value(forKey: "token")! as? String
getData()
}
func getData () {
let httpHeaders = ["Authorization": token!,
"Accept": "application/json"]
Alamofire.request(REST_API.MAIN_URL_DEV + REST_API.SHIPMENTS + "/" + number! ,encoding: JSONEncoding.default, headers: httpHeaders)
.responseString { response in
if let JSON = response.result.value {
self.json = JSON
// print(JSON)
if let jsonObj = self.json.parseJSONString {
if let data = jsonObj as? NSDictionary {
if let obj = DetailListJson4Swift_Base(dictionary: data) {
if obj.status?.code == 200 {
self.detail_data = obj.data
print("////==================== DATA", obj.data!, self.detail_data!)
self.loadingView.isHidden = true
self.tableView.reloadData()
} else {
print("Status: Error code")
MyAlertController.doAlert("Error", alertMessage: "something wrong, try again late")
}
} else {
MyAlertController.doAlert("Error", alertMessage: "Unable to construct movie object")
print("Unable to construct movie object")
}
} else {
MyAlertController.doAlert("Error", alertMessage: "Unable to interpret parsed object as dictionary")
print("Unable to interpret parsed object as dictionary")
print(jsonObj)
}
}
}
}
}
#IBAction func accept(_ sender: Any) {
}
}
extension TableVC {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if detail_data != nil {
if section == 0 {
return 3
} else if section == 1 {
return (detail_data?.waypoints?.count)!
} else if section == 2 {
return 1
}
}
return 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let headerTVC = tableView.dequeueReusableCell(withIdentifier: "HeaderTVC", for: indexPath) as! HeaderTVC
headerTVC.code.text = detail_data?.id!
headerTVC.price.text = detail_data?.price?.total!
headerTVC.distamce.text = detail_data?.distance!
return headerTVC
}
if indexPath.row == 1 {
let distanceTVC = tableView.dequeueReusableCell(withIdentifier: "DistanceTVC", for: indexPath) as! DistanceTVC
return distanceTVC
}
if indexPath.row == 2 {
let mapTVC = tableView.dequeueReusableCell(withIdentifier: "MapTVC", for: indexPath) as! MapTVC
return mapTVC
}
if indexPath.row == 4 {
let bottomTVC = tableView.dequeueReusableCell(withIdentifier: "BottomTVC", for: indexPath) as! BottomTVC
return bottomTVC
}
// the other cells should contains title and subtitle:
let infoTVC = tableView.dequeueReusableCell(withIdentifier: "InfoTVC", for: indexPath) as! InfoTVC
return infoTVC
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}

Related

How do you display JSON API data in a table view?

I am not able to display the JSON data in my table view. I don't know why. I tried to get the JSON data, but I am not able to display it on screen in a table format.
This is the model:
class PastTripsVC: UIViewController {
var past = [PastRide]()
#IBOutlet weak var mTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let nibCell = UINib(nibName: "PastTableView", bundle: nil)
mTable.register(nibCell, forCellReuseIdentifier: "cell")
apiCalling()
}
func apiCalling(){
if let url = URL(string: "https://pincood.com/pincood/public/api/user/trips") {
var request = URLRequest(url: url)
request.allHTTPHeaderFields = [
"Content-Type": "application/json",
"Session": "fb4e7f9b-0f31-4709-",
"AUthorization":"<some key>"
]
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil else { return }
guard let data = data else { return }
do{
let codabledata = try JSONDecoder().decode([PastRide].self, from: data)
print(codabledata)
DispatchQueue.main.async {
self.past = codabledata
self.mTable.reloadData()
}
} catch {
print(error)
}
}.resume()
}
}
In the extension we try:
extension PastTripsVC : UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return past.count
print(past.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PastTableView
cell.usernm.text = past[indexPath.row].provider.firstName
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let details : PastDetailView = self.storyboard?.instantiateViewController(withIdentifier: "PastDetailView") as! PastDetailView
navigationController?.pushViewController(details, animated: true)
}
}
You need to set table view's delegate and datasource properties in viewDidLoad.
Update your viewDidLoad to look like this:
override func viewDidLoad() {
super.viewDidLoad()
let nibCell = UINib(nibName: "PastTableView", bundle: nil)
mTable.register(nibCell, forCellReuseIdentifier: "cell")
mTable.delegate = self
mTable.datasource = self
apiCalling()
}

Swift 5 - make tableview wait until data from api call comes back (using multiple tableviews)

Issue: Fatal error when View is loading. I know the problem is because there is no data available when to table view is trying to load. But, because I am using multiple TableViews in one UI I have to force the cell return in CellForRowAt.
Is there a better way of setting up different data for each TableView?
THANKS FOR THE HELP!
import UIKit
class NewCustomTaskVC: UIViewController {
#IBAction func CancelPressed (_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBOutlet weak var taskTypeSelectionBtn: UIButton!
#IBOutlet weak var FrameSelectionBtn: UIButton!
#IBOutlet weak var AssignSelectionBtn: UIButton!
#IBAction func SelecttaskTypePressed(_ sender: Any) {
if tableViewTaskType.isHidden {
self.tableViewTaskType.isHidden = false
self.tableViewTaskType.rowHeight = 43.5
} else {
self.tableViewTaskType.isHidden = true
}
}
#IBAction func SelectFramePressed(_ sender: Any) {
if tableViewFrame.isHidden {
self.tableViewFrame.isHidden = false
} else {
self.tableViewFrame.isHidden = true
}
}
#IBAction func SelectAssignToPressed(_ sender: Any) {
if tableViewAssignTo.isHidden {
self.tableViewAssignTo.isHidden = false
} else {
self.tableViewAssignTo.isHidden = true
}
}
#IBOutlet weak var tableViewTaskType: UITableView!
#IBOutlet weak var tableViewFrame: UITableView!
#IBOutlet weak var tableViewAssignTo: UITableView!
var cellID = ""
var array = ["String", "Test", "Next","Test 2", "Test 3"]
override func viewDidLoad() {
super.viewDidLoad()
getData()
tableViewTaskType.isHidden = true
tableViewFrame.isHidden = true
tableViewAssignTo.isHidden = true
tableViewTaskType.delegate = self
tableViewFrame.delegate = self
tableViewAssignTo.delegate = self
tableViewTaskType.dataSource = self
tableViewFrame.dataSource = self
tableViewAssignTo.dataSource = self
self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")
}
func getData () {
//dispatchGroup.enter()
var count = 0
APICallBack.getFramesData(completion: { success in
if success == true {
print("frames success")
count += 1
} })
APICallBack.getTaskTypeData { success in
if success == true {
print("task success")
count += 1
}
}
APICallBack.GETUserData(completion: { success in
if success == true {
print("user success")
count += 1
} })
if count == 3{
DispatchQueue.main.async {
self.tableViewTaskType.reloadData()
self.tableViewAssignTo.reloadData()
self.tableViewFrame.reloadData()
print("ALL COMPLETE")
}
}
}
}
extension NewCustomTaskVC : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count = 1
switch tableView {
case tableViewTaskType:
count = TaskTypeData.typeModel.count
case tableViewFrame:
count = FramesData.framesModel.count
case tableViewAssignTo:
count = CustomerData.customerModel.count
default:
print("none")
return count
}
//return 5
return count
}
**PROBLEM IS HERE
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.tableViewTaskType{
cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell!.textLabel!.text = TaskTypeData.typeModel[indexPath.row].TaskTypeName
// cell!.textLabel?.text = array[indexPath.row]
}
if tableView == tableViewFrame{
cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
cell!.textLabel!.text = FramesData.framesModel[indexPath.row].FrameName
// cell!.textLabel?.text = array[indexPath.row]
}
if tableView == self.tableViewAssignTo {
cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
cell!.textLabel!.text = UserData.userModel[indexPath.row].UserFirst
// cell.textLabel?.text = array[indexPath.row]
}
// let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
// cell.textLabel?.text = array[indexPath.row]
return cell!
}
** TO HERE!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = array[indexPath.row]
print(item)
tableViewTaskType.isHidden = true
}
}
My UI View:
The error I get if I don't force it:
I assume that you want to display an empty "placeholder" cell if the data source array is empty. You need to check explicitly for that condition in your cellForRow function.
As far as co-ordinating the fetch from multiple API endpoints, you can use a DispatchGroup - Some commented code indicates you may have tried this.
override func viewDidLoad() {
super.viewDidLoad()
tableViewTaskType.isHidden = true
tableViewFrame.isHidden = true
tableViewAssignTo.isHidden = true
tableViewTaskType.delegate = self
tableViewFrame.delegate = self
tableViewAssignTo.delegate = self
tableViewTaskType.dataSource = self
tableViewFrame.dataSource = self
tableViewAssignTo.dataSource = self
self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")
getData()
}
func getData () {
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
APICallBack.getFramesData(completion: { success in
if success == true {
print("frames success")
}
dispatchGroup.leave()
})
APICallBack.getTaskTypeData { success in
if success == true {
print("task success")
}
dispatchGroup.leave()
}
APICallBack.GETUserData(completion: { success in
if success == true {
print("user success")
}
dispatchGroup.leave()
})
dispatchGroup.notify {
self.tableViewTaskType.reloadData()
self.tableViewAssignTo.reloadData()
self.tableViewFrame.reloadData()
print("ALL COMPLETE")
}
}
extension NewCustomTaskVC : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch tableView {
case tableViewTaskType:
return max(1,TaskTypeData.typeModel.count)
case tableViewFrame:
return max(1,FramesData.framesModel.count)
case tableViewAssignTo:
return max(1,CustomerData.customerModel.count)
default:
fatalError("Unexpected table view")
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch tableView {
case self.tableViewTaskType:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
if !TaskTypeData.typeModel.isEmpty {
cell.textLabel!.text = TaskTypeData.typeModel[indexPath.row].TaskTypeName
}
return cell
case tableViewFrame:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
if !FramesData.framesModel.isEmpty {
cell!.textLabel!.text = FramesData.framesModel[indexPath.row].FrameName
}
return cell
case self.tableViewAssignTo:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
if !UserData.userModel.isEmpty {
cell!.textLabel!.text = UserData.userModel[indexPath.row].UserFirst
}
return cell
default:
fatalError("Unexpected Tableview")
}
}
you can set tableView.dataSource & tableView.delegate to self when your data is back
There is multiple problems with your code.
1) You call get data before your table view had registered it cells.
So if your API would load data immediately table view will be call dataSource methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
but since the
self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")
called in the end of viewDidLoad, your would get crash when you dequeue your cells in cellForAtIndexPath method.
The solution is to move getData call to the end of viewDidLoad method.
2) If you want to display all tables data at one time (when API is complete loading getFramesData, getTaskTypeData and GETUserData) you would need to synchronise this callbacks. You could do this with DispatchGroup.
func getData () {
let apiDispatchGroup = DispatchGroup()
APICallBack.getFramesData { success in
apiDispatchGroup.leave()
}
apiDispatchGroup.enter()
APICallBack.getTaskTypeData { success in
apiDispatchGroup.leave()
}
apiDispatchGroup.enter()
APICallBack.GETUserData { success in
apiDispatchGroup.leave()
}
apiDispatchGroup.enter()
apiDispatchGroup.notify(queue: DispatchQueue.main) {
self.tableViewTaskType.reloadData()
self.tableViewAssignTo.reloadData()
self.tableViewFrame.reloadData()
}
}
3) It's not good idea to use one dataSOurce class for mutltiple UITableView, because of dataSource become god object. The better approach is to use one ContainerViewController that contains three child UITableViewController, and pass data to the childs when data has loaded from the API.
It is perfectly fine to have multiple view controllers in one screen. So I suggest that you create three view controllers, one for each table view. And each table view has its own datasource. Then use a custom container view controller as described here: https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller

How to get row index from UITableView which the array list made by append to a class

How to get row index from UITableView which the array list made by append to a Object Class.
And I want to get the row index based on the value from the object, I needed that for scroll to a row which I only know a value from object, but don't know which the row index.
Below is the code for create a array and show to the UITableView.
let paging: Int
let obj: Any
var currentAyaPlaying: Int?
var listArr = [] as [Any]
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 700
tableView.rowHeight = UITableView.automaticDimension
tableView.allowsSelection = true
if paging == Paging.SURA {
let sura = obj as! Sura
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...sura.ayas {
listArr.append(Mark(sura.index, aya))
}
} else if (paging == Paging.JUZ){
let juz = obj as! Juz
for suras in juz.sura_start...juz.sura_end {
let sura = MetaData().mSuras[suras - 1]
if juz.sura_start == suras {
for aya in juz.aya_start...(juz.sura_end == suras ? juz.aya_end : sura.ayas) {
listArr.append(Mark(suras, aya))
}
} else if juz.sura_end == suras {
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...juz.aya_end {
listArr.append(Mark(suras, aya))
}
} else {
listArr.append(Sura(sura.index, sura.start, sura.ayas, sura.type, sura.img, sura.name, sura.translate))
for aya in 1...sura.ayas {
listArr.append(Mark(suras, aya))
}
}
}
}
NotificationCenter.default.addObserver(self, selector: #selector(appearNotifAudioReload(_:)), name: NSNotification.Name(rawValue: NotifKey.actAudioReloadFromParentToChild), object: nil)
}
#objc func appearNotifAudioReload(_ notification: Notification) {
guard let sura = notification.userInfo?["sura"] as? Int else { return }
guard let aya = notification.userInfo?["aya"] as? Int else { return }
print("sura: \(sura)")
print("aya: \(aya)")
self.currentAyaPlaying = aya
if paging == Paging.SURA {
let indexPath = NSIndexPath(row: self.currentAyaPlaying!, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
} else if paging == Paging.JUZ {
let IStackInHere = Mark(sura, aya) // how to get the row index from this data?
let indexPath = NSIndexPath(row: IStackInHere, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
}
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listArr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (listArr[indexPath.row] as? Sura) != nil {
tableView.register(UINib(nibName: identifierAyaHeader, bundle: Bundle.main), forCellReuseIdentifier: identifierAyaHeader)
let cell = tableView.dequeueReusableCell(withIdentifier: identifierAyaHeader, for: indexPath) as! AyaCellHeader
let data = listArr[indexPath.row] as! Sura
cell.configureWithData(data)
return cell
}
tableView.register(UINib(nibName: identifierAya, bundle: Bundle.main), forCellReuseIdentifier: identifierAya)
let cell = tableView.dequeueReusableCell(withIdentifier: identifierAya, for: indexPath) as! AyaCell
let data = listArr[indexPath.row] as! Mark
cell.configureWithData(data)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (listArr[indexPath.row] as? Mark) != nil {
tableView.deselectRow(at: indexPath, animated: false)
let mark = listArr[indexPath.row] as! Mark
showActionBottom(mark: mark)
}
}
I want to get it in the condition if paging == Paging.JUZ in the func appearNotifAudioReload, I just try to get it with:
let index = listArr.firstIndex{$0 === Mark(sura, aya)}
But no lucky and error
"Binary operator '===' cannot be applied to operands of type 'Any' and
'Mark'"
I know this forum is not to solve my coding problems, but right now I'm really troubled.
Thanks in advance.
You need to use == (to equal signs) to compare equality. Assuming the Mark struct conforms to Equatable, you can use the following:
let index = listArr.firstIndex { $0 as! Mark == Mark(sura, aya) }

Swift 3 - Setting variable in TableViewController swift file depending on cell clicked

I'm trying to set the a string depending on which cell in a tableView is clicked. The BlueLineTableViewController is the one which should capture the user's click.
import UIKit
class BlueLineTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return bluelinestations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "bluelinecell", for: indexPath)
let station = bluelinestations[indexPath.row]
cell.textLabel?.text = station.name
cell.imageView?.image = UIImage(named: station.image)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let row = indexPath.row
if row == 0 {
BlueBelmontTableViewController().feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
}
if row == 1 {
BlueBelmontTableViewController().feed="http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40820&outputType=JSON"
}
}
The BlueBelmontTableViewController's feed variable should change/be set to another url depending on which cell is clicked in the BlueLineTableViewController.
import UIKit
class BlueBelmontTableViewController: UITableViewController {
class Destinations {
var destination: String = ""
var time: String = ""
}
var feed = ""
var dataAvailable = false
var records = [Destinations]()
override func viewDidLoad() {
super.viewDidLoad()
parseData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
for r in records {
r.time = ""
r.destination = ""
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataAvailable ? records.count : 15
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (dataAvailable) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let destinationRow = records[indexPath.row]
cell.textLabel?.text = destinationRow.destination
cell.detailTextLabel?.text = destinationRow.time
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlaceholderCell", for: indexPath)
return cell
}
}
func parseData() {
guard let feedURL = URL(string: feed) else {
return
}
let request = URLRequest(url: feedURL)
let task = URLSession.shared.dataTask(with: request) {(data, response, error) in
if error != nil
{
print("Error")
}
else {
if let content = data {
do {
let json = try JSONSerialization.jsonObject(with: content, options: []) as? [String:Any] ?? [:]
print(json)
if let ctattimetable = json["ctatt"] as? [String:Any] {
if let estArrivalTime = ctattimetable["eta"] as? [[String:Any]] {
for item in estArrivalTime{
if let headingTowards = item["destNm"] as? String,
let arrivalTime = item["arrT"] as? String {
let record = Destinations()
record.destination = headingTowards
record.time = arrivalTime
self.records.append(record)
}
self.dataAvailable = true
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
catch {
}
}
}
}
task.resume()
}
}
I've tried setting the url in the didSelectRowAt method depending on the indexPath.row as can be seen in BlueLineTableViewController, but it does not seem to do anything. Does anybody know how I would go about doing this?
Below is the Main.storyboard of this part of my project:
Your are not able to pass value because you are setting feed property to the completely new instance of BlueBelmontTableViewController not the one that is added in navigation stack using your segue that you have created from your UITableViewCell to BlueBelmontTableViewController.
What you need to do is override prepareForSegue in your BlueLineTableViewController to pass your value to BlueBelmontTableViewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! BlueBelmontTableViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
if indexPath.row == 0 {
vc.feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
}
if indexPath.row == 1 {
vc.feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40820&outputType=JSON"
}
}
}
instead of
BlueBelmontTableViewController().feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
use
self.feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
beacause BlueBelmontTableViewController() is initialing new instance of BlueBelmontTableViewController and you want to change the instance you already have so you should use self instead of creating new instance.

Why am I getting the error: fatal error: unexpectedly found nil while unwrapping an Optional value?

I have a TableViewController below that I am trying to populate with a query request from Parse. The idea is that the call (which I have checked and is returning the necessary information) then fills the arrays, which I then use to populate the TableViewCells. These cells also have a custom class ('TableViewCell').
For some reason, 'self.tableView.reloadData()' is definitely causing the crash. When I remove it, it doesn't crash but the tableviewcells don't update with the parse information. Any ideas?
import UIKit
import Parse
class AuctionViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "Cell")
}
var capArray = [String]()
var imageDic = [String: [PFFile]]()
var priceArray = [Int]()
override func viewDidAppear(animated: Bool) {
capArray.removeAll(keepCapacity: true)
imageDic.removeAll(keepCapacity: true)
priceArray.removeAll(keepCapacity: true)
let query = PFQuery(className: "SellerObject")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for o in objects {
if o.objectForKey("caption") != nil && o.objectForKey("imageFile") != nil && o.objectForKey("price") != nil {
let cap = o.objectForKey("caption") as? String
self.capArray.append(cap!)
let imdic = o.objectForKey("imageFile") as? [PFFile]
self.imageDic[cap!] = imdic
let price = o.objectForKey("price") as? String
let priceInt = Int(price!)
self.priceArray.append(priceInt!)
print(self.capArray)
print(self.imageDic)
print(self.priceArray)
}
self.tableView.reloadData()
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return capArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.captionLabel.text = self.capArray[indexPath.row]
return cell
}
First of all, you are not checking cap, imdic, price by type. And reloading tableView many times in cycle. Replace
for o in objects {
if o.objectForKey("caption") != nil && o.objectForKey("imageFile") != nil && o.objectForKey("price") != nil {
let cap = o.objectForKey("caption") as? String
self.capArray.append(cap!)
let imdic = o.objectForKey("imageFile") as? [PFFile]
self.imageDic[cap!] = imdic
let price = o.objectForKey("price") as? String
let priceInt = Int(price!)
self.priceArray.append(priceInt!)
print(self.capArray)
print(self.imageDic)
print(self.priceArray)
}
self.tableView.reloadData()
}
with
for o in objects {
if let cap = o.objectForKey("caption") as? String,
let imdic = o.objectForKey("imageFile") as? [PFFile],
let priceInt = (o.objectForKey("price") as? String).flatMap({ Int($0))}) {
self.capArray.append(cap)
self.imageDic[cap] = imdic
self.priceArray.append(priceInt)
print(self.capArray)
print(self.imageDic)
print(self.priceArray)
}
}
self.tableView.reloadData()
Also, don't dequeue cell that way. Replace
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.captionLabel.text = self.capArray[indexPath.row]
return cell
}
with
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? TableViewCell else {
assertionFailure("cell for index-path:\(indexPath) not found")
return UITableViewCell()
}
cell.captionLabel.text = self.capArray[indexPath.row]
return cell
}
But I think that problem could always be inside TableViewCell class🤔 For example, captionLabel could be nil.

Resources