API calls through Switch Statements - ios

I have two tableViews, The first table view has fixed data which never will be changed. When a user taps on a specific cell for example cell number 1, an API 1 is called and the 2nd table view is loaded with the returned data when cell number 2 is tapped API 2 is called the 2nd table view is loaded with the returned data.
To solve this issue I have tried this.
In my first Table View I record of which table cell was tapped and send that information to the 2nd table view via prepare for segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destination = segue.destinationViewController as? BioListTableViewController {
let indexPath = self.tableView.indexPathForSelectedRow()
if let row:Int = indexPath?.row {
// PASS which cell was tapped by the user
destination.cellTapped = row
}
}
}
Then within my 2nd table view I use a switch statement which checks whether the cell tapped was 0,1,2 and so on. And based on that a switch case is run. Each switch case has a different function which calls a different API. See below:
import UIKit
struct Note {
var name:String
var job:String
}
struct WeatherSummary {
var id: String
}
class BioListTableViewController: UITableViewController {
var cellTapped = Int()
#IBOutlet var tableview: UITableView!
private var notes = Array<Note>()
var bioArray = NSArray(){
didSet{
tableview.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
switch cellTapped {
case 0:
test()
case 1:
testTwo()
default:
println("Error")
}
var newItem:Note = Note(name: "", job: "")
for x in bioArray {
if let id = x["employeeName"] as? String{
newItem.name = id
}
}
}
func test() {
println("This is TWEST")
var weatherArray = [WeatherSummary]()
var request = NSMutableURLRequest(URL: NSURL(string: "myAPI-Link")!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "GET"
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
var err: NSError?
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSArray
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
dispatch_async(dispatch_get_main_queue()) {
var alert = UIAlertController(title: "Alert", message: "Oops! Wrong Details, Try Again", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}else {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
var newWeather = WeatherSummary(id:"")
if let parseJSON = json {
for weather in parseJSON {
if let id = weather["employeeName"] as? String{
println(" LOOK HERE \(id)")
newWeather.id = id
}
}
weatherArray.append(newWeather)
self.bioArray = parseJSON
} else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume()
}
func testTwo(){
println("THIS IS TEST 2")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return self.bioArray.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("bioCell", forIndexPath: indexPath) as! UITableViewCell
let weatherSummary: AnyObject = bioArray[indexPath.row]
if let id = weatherSummary["employeeName"] as? String //Dont know the exact syntax.
{
cell.textLabel?.text = id
}
if let job = weatherSummary["jobTitle"] as? String {
cell.detailTextLabel?.text = job
}
return cell
}
}
My Issue:
My Issue is that when I println the returned data it is being printed and I can see it. But my 2nd table view is empty. It does not display the data. I am not sure why the data is not being displayed on the 2nd table view. I can see the data by using println which proves that the API is actually returning real data.
Any suggestions?
Apologies for any mistakes. Please let me know if I have made a mistake and I will fix it.
Thank you.

Hard to answer this without seeing the data or the Storyboard. But a few things you should check set a breakpoint and make sure it is calling:
didSet method of bioArray
is numberOfRowsInSection hit and returning something?
is the delegate and datasource set properly?
is cellForRowAtIndexPath hit and do you have keys named: employeeName and jobTitle
Please check these things first.

I figured out how to fix the issue. Thought I would answer my own question.
Basically I had to reload my table view to display the data.
So I did the following:
didSet{
dispatch_async(dispatch_get_main_queue()) {
self.tableview.reloadData()
}
}
By doing the above my issue was solved. Once I tapped the cell, it took a few seconds but it reloaded my table view once the data was returned from the API and displayed it.

Related

TableViewController populates on search, but won't load initial view

Swift 5, iOS 12, Xcode 10
I finally implemented a search bar on my ListingsViewController and it's working really well -- but the initial data isn't populating into the table.
I realize that this is a clumsy implementation, but I'm learning as I go and I'm using only code that I can understand. I've been at this for two days -- I've tried creating a Struct and bringing in the data that way, but I can't even get an Array. I've tried bringing it in as an NSArray and an Array and an Object, but either I can't get the initial table to load, or I can't get data to parse out at all, or I can't get the search to work.
I suspect it has something to do with how, when or where I'm calling the loadData() function but I just can't figure it out.
class ListingsViewController: UITableViewController, UISearchResultsUpdating {
var tableData = [String]()
var filteredTableData = [String]()
var resultSearchController = UISearchController()
func updateSearchResults(for searchController: UISearchController) {
filteredTableData.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (tableData as NSArray).filtered(using: searchPredicate)
filteredTableData = array as! [String]
self.tableView.reloadData()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
tableData = [String]()
loadData()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
tableView.tableHeaderView = controller.searchBar
return controller
})()
tableView.reloadData()
}
func loadData() {
guard let url = URL(string: "--------------") else {return }
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data, error == nil else {
print(error?.localizedDescription ?? "Response Error")
return
}
do {
let jsonResponse = try JSONSerialization.jsonObject(with: dataResponse, options: [])
guard let jsonArray = jsonResponse as? [[String:Any]] else { return }
for dic in jsonArray {
self.tableData.append(dic["name"] as! String)
// self.feedItems.append(Listing(id: (dic["id"] as! String), city_id: (dic["city_id"] as! String), category: (dic["category"] as! String), sub_category: (dic["sub_category"] as! String), name: (dic["name"] as! String), phone: (dic["phone"] as! String), email: (dic["email"] as! String), website: (dic["website"] as! String), address: (dic["address"] as! String), comment: (dic["comment"] as! String), recommendedby: (dic["recommendedby"] as! String)))
}
} catch let parsingError {
print("Error", parsingError)
}
}
self.tableView.reloadData()
task.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (resultSearchController.isActive) {
return filteredTableData.count
} else {
return tableData.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.textColor = .white
cell.backgroundColor = .black
cell.tintColor = .lightText
if (resultSearchController.isActive) {
cell.textLabel?.text = filteredTableData[indexPath.row]
return cell
} else {
cell.textLabel?.text = tableData[indexPath.row]
return cell
}
}
}
I'm expecting the entire list of Listings to appear when I switch to the ListingsViewController from the tab bar. Instead, I get a blank table.
HOWEVER, If I tap into the search bar and start typing, though, I get matching results -- and when I cancel the search, I can see all of the results in the table.
(Also, when I tap into the search bar, my navigation bar goes away and doesn't come back, even when I cancel the search. Even if I switch to a different tab and come back. Haven't been able to figure that one out.)
You are missing the delegate and data source for the table view
add this:
class ListingsViewController: UITableViewController, UISearchResultsUpdating,UITableViewDelegate,UITableViewDataSource {
//your class code here
}
and on your viewDidLoad add this:
self.tableView.delegate = self
self.tableView.dataSource = self
that should work, Please notice that after you called the delegate and data source your cell for row and numbers of rows functions will be called so make sure the array you are using is not nil by then
I saw you haven't been missing delegate and data source for the table view.
You must register delegate and data source for viewcontroler. where you will display data.
Please insert this code on your viewDidLoad
self.tableView.delegate = self
self.tableView.dataSource = self
Change your load day to this
func loadData() {
guard let url = URL(string: "--------------") else’s {return }
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data, error == nil else {
print(error?.localizedDescription ?? "Response Error")
return
}
do {
let jsonResponse = try JSONSerialization.jsonObject(with: dataResponse, options: [])
guard let jsonArray = jsonResponse as? [[String:Any]] else { return }
for dic in jsonArray {
self.tableData.append(dic[“name”] as! String
}
DispatchQueue.main.async {
print("call to reload data")
self.tableView.reloadData()
}
} catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
}
your are callig to reload data before the completion block, you can check it with the following print("calling to reloadData") then test my solution and see that works, make a print statamente for JsonArray to check where is called, you must reload the tableViewData after the async func is terminated.

Get JSON data and display in tableview Xcode

I'm creating a IOS program to download json data from url and display in table view of ios. i have issue to download JSON (every 10 second )in loginpage view controller and parse JSON data to tableview controller. Before posting this, i have try to search many times but can't find solution. Below is StoryBoad and the code
Story Board
User will login, after login success, JSON data will be loaded (userlogin = true). Below code in login class loginPage: UIViewController
#IBOutlet weak var usernameLogin: UITextField!
#IBOutlet weak var passwordLogin: UITextField!
#IBAction func loginPress(_ sender: Any) {
username = usernameLogin.text!
password = passwordLogin.text!
let request = NSMutableURLRequest(url: NSURL(string: "http://talectric.com/wp-admin/a_p/users/userlogin.php")! as URL)
request.httpMethod = "POST"
let postString = "username=\(username)&password=\(password)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error!)")
return
}
else
{
do {
let respondString = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
print(respondString!)
let message = respondString?["message"] as! String
if message == "Check Pass" {
userlogin = true
DispatchQueue.main.async {
let TabViewPageController = self.storyboard?.instantiateViewController(withIdentifier: "TabViewPageID") as! TabViewPage
self.present(TabViewPageController, animated: true, completion: nil)
}
}
else {
DispatchQueue.main.async {
let alertController = UIAlertController(title: "Login", message:
"Username or Password is not correct", preferredStyle: UIAlertController.Style.alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
}
catch let error as NSError {
print(error.debugDescription)
}
}
}
task.resume()
}
after userlogin = true, #objc func taskdo() will load JSON data to nodeidArray but second download not overwrite first element of nodeidArray and nodeidArray is inserted after last element ( i just want nodeidArray to be overwrited)
import UIKit
var timer = Timer()
var userlogin = false
struct Data {}
var username = String()
var password = String()
class loginPage: UIViewController{
var nodeidArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
timerstart()
}
func timerstart()
{
timer = Timer.scheduledTimer(timeInterval: 5, target: self,selector: #selector(loginPage.taskdo),userInfo:nil,repeats: true)
}
#objc func taskdo()
{
if userlogin == true{
let request = NSMutableURLRequest(url: NSURL(string: "http://talectric.com/wp-admin/a_p/iot/read_all.php")! as URL)
request.httpMethod = "POST"
let postString = "username=\(username)&password=\(password)&authen=wdwfesf9329140dsvfxkciospdkm"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error!)")
return
}
else
{
do {
if let respondString = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
if let nodedata = respondString.value(forKey: "nodedata") as? NSArray {
for node in nodedata{
if let nodeDict = node as? NSDictionary {
if let nodeid = nodeDict.value(forKey: "nodeid"){
self.nodeidArray.insert(nodeid as! String, at: 0)
}
}
}
}
}
// print(respondString!)
//let message = respondString?["numberofnodeid"] as! Int
//let nodedata = respondString!.value(forKey: "nodedata")//
// let nodeid = (nodedata as AnyObject).value(forKey: "nodeid")
// print(respondString!.value(forKey: "nodedata")!)
print(self.nodeidArray)
let defaults = UserDefaults.standard
defaults.set(self.nodeidArray, forKey: "YourKey")
}
catch let error as NSError {
print(error.debugDescription)
}
}
}
task.resume()
}
}
}
After download JSON in LoginViewController, i can not paste data to tableview controller. I have try to change nodeidArray to static in LoginPage but can't use static variable in #objc func taskdo(). I try UserDefaults also but can't get data in TableViewController (NodeDataPage)
i have test tableview success with Local Variable in Class NodeDataPage but can't test variable from other viewcontroller
import UIKit
class NodeDataPage:
UIViewController,UITableViewDelegate,UITableViewDataSource {
//var nodeidname = ["nodeid1","nodeid2","nodeid3"]
var testArray : [String]() = UserDefaults.standard.objectForKey("YourKey") {
var nodeidname : [NSString] = testArray! as! [NSString]
println(readArray)
}
#IBOutlet weak var tableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nodeidname.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:"nodeCell",for: indexPath)
cell.textLabel?.text = nodeidname[indexPath.row]
return cell
}}
I specify the questions:
How can i transfer JSON data (download in LoginPage VC) to Table View VC (NodeDataPage VC) ?
How can i run JSON download function in LoginPage VC every 10s with Question 1 also (i try static variable to get in other view and can't run in #objc func taskdo() ?
I want to run JSON download data every 10s after userlogin. Should i put this function in LoginPage VC or other view because i need to get data from server continuously ?
How can i run JSON download func when the app is hidden (not be killed) ?
i have tried to research small part but now it become more complicated. Please help me.
Thank you
Create a separate class like "DataManager" which holds all your data (nodeidArray) as well as makes calls to server to fetch from web service every 10 seconds.
Once user logs in successfully, show the NodeDataPage. In viewDidLoad of this class, create DataManager object and call the method that handles the timer and fetching data from server.
Use notification or observer design pattern to intimate the NodeDataPage to get the data from DataManager and reload the tableview.
Hope I am able to answer your questions.

Swift tableView slow and scroll lag

I am Pulling data from a json API Call the table view populates but is very slow and lags when scrolling down how do i speed up the loading of the table. I am new to swift and xcode any tips would be appreciates
import Foundation
import UIKit
class featuredViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
// Array for JSON Data
var property: [featuredClass.property] = []
var imageArray = [String]()
var imageCollection = [[String]]()
var refreshControl: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
self.getProperties()
// Do any additional setup after loading the view, typically from a nib.
refreshControl = UIRefreshControl()
refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: #selector(featuredViewController.getProperties), for: UIControlEvents.valueChanged)
tableView.addSubview(refreshControl)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/***********************************************************************************************/
func getProperties() {
let downloadTask = APICalls.getFeatured()
URLSession.shared.dataTask(with: downloadTask, completionHandler: {(data, response, error) -> Void in
if let httpResponse = response as? HTTPURLResponse {
print("statusCode: \(httpResponse.statusCode)")
}
/******** Parse JSON **********/
do { // A Dictionary of Dictionaries
let jsonObject = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
if let jsonDict = jsonObject as? NSDictionary {
// Do smthg.
//print(jsonDict) // Debug the json
let meCount = Int((jsonDict.count)) - 1; //get number to use for our loop
for index in 0...meCount {
for (_, value) in jsonDict { //Turns every key's value into a dictionary
// Fill property struct from json
self.property.append(featuredClass.property.init(jsonDict: value as! NSDictionary))
//print(self.property) // Uncomment for debugging
/** Get Image 0 for featured Image **/
let myData = self.property[index].image
// print(myData ?? "Error")
if myData?["0"] != nil {
let myData2 = myData?["0"] as! NSDictionary
self.imageArray.append(myData2["url"] as! String)
//print(myData2["url"] as! String)
}
else {
self.imageArray.append("\(#imageLiteral(resourceName: "property-placeholder-800x500"))")
}
/* ENd Get image 0 */
}
}
}
}catch {
//...
}
let meCount = (self.property.count)-1
/******** End Parse JSON **********/
//print(meCount)
if meCount != -1 {
}
else {
// Show alert view
let contactAddedAlert = UIAlertController(title: "Error: Check if Access Key is correct",
message: nil, preferredStyle: .alert)
contactAddedAlert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(contactAddedAlert, animated: true, completion: nil)
}
/******** Reload table View **********/
OperationQueue.main.addOperation({
self.tableView.reloadData()
self.refreshControl.endRefreshing()
}) }).resume()
}
/***********************************************************************************************/
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return property.count
}
/***********************************************************************************************/
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellFeatured") as! featuredTableViewCell
cell.addressLabel.text = property[indexPath.row].address
cell.cityNameLabel.text = property[indexPath.row].cityName
let imgURL = NSURL(string: imageArray[indexPath.row])
if imgURL != nil {
let data = NSData(contentsOf: (imgURL as URL?)!)
cell.imgView.image = UIImage(data: data! as Data)
}
return cell
}
}
NSData(contentsOf: (imgURL as URL?)!) is synchronous. Please refer to the SDK document: https://developer.apple.com/reference/foundation/nsdata/1547245-datawithcontentsofurl
Which state that:
Do not use this synchronous method to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network, resulting in a poor user experience, and in iOS, may cause your app to be terminated.
Instead, for non-file URLs, consider using the dataTaskWithURL:completionHandler: method of the NSURLSession class. See URL Session Programming Guide for details.
You can use this pod to boost your speed
https://github.com/rs/SDWebImage
It will be great to load images.

Retrieving data back from server side based on input

I'm doing a school project, its's multiple tables and tabBarControllers. Now, I want to display return data back from server side based on selected row. I managed to pass selected row from View to another, and I believe there is nothing wrong with passing it to the server side, too. The problem is when retrieving the data back from the server.
Here is Course View
// This array is to hold data coming from server side
var course: NSArray = []
// Assign data that come from DepartmentView
public var department: String? = nil
var myURL = URL(string: "http://localhost/masterProject/scripts/courses.php")
override func viewDidLoad()
{
super.viewDidLoad()
self.title = "Courses"
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
// This is just to make sure it gets data and not nil
let vDepartment = department!
// Create a request
var request = URLRequest(url: myURL!)
request.httpMethod = "POST";
// Create a parameter to be sent to server side and based on this
// data I want to get data back that belong to it.
let postParameter = "department=\(vDepartment)";
request.httpBody = postParameter.data(using: String.Encoding.utf8)
// Here I Create and send dataTask
let task = URLSession.shared.dataTask(with: request)
{ (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
if(error != nil)
{
self.alertMessage(message: (error?.localizedDescription)!)
return
}
// This is supposed to read data from server side and display it
// in Course table view.
self.course = try! JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSArray
}
}
task.resume()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return course.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "courseCell", for: indexPath) as! CourseTableViewCell
let main = course[indexPath.row] as! NSDictionary
cell.courseName.text = (main["name"] as! String)
cell.courseNumber.text = (main["number"] as! String)
return cell
}
func alertMessage(message: String)
{
let alert = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
Department view
var departments: NSArray = []
var myURL = URL(string: "http://localhost/masterProject/scripts/department.php")
override func viewDidLoad()
{
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool)
{
self.title = "Departments"
super.viewWillAppear(animated)
let data = NSData(contentsOf: myURL!)
departments = try! JSONSerialization.jsonObject(with: data! as Data, options: .mutableContainers) as! NSArray
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
// #warning Incomplete implementation, return the number of rows
return departments.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let data = departments[indexPath.row] as! NSDictionary
cell.textLabel?.text = (data["name"] as! String)
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "showDepCourses"
{
if let indexPath = tableView.indexPathForSelectedRow
{
let courseVC = segue.destination as! CourseTableViewController
let data = departments[indexPath.row] as! NSDictionary
courseVC.department = (data["name"] as! String)
}
}
}
}
Here are the picture for both Views
department view
course view
I'm supposed get the right data based on selected row but instead it shows nothing.
self.tabeView.reloadData() was missing the whole time.
This is the answer for the question:
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
// Just to make sure "Optional" keyword not send as POST PERAMETER
let selectedDep = department!
// Create a request
var request = URLRequest(url: myURL!)
request.httpMethod = "POST";
// Create a parameter to be sent to server side and based on this
// data I want to get data back that belong to it.
let postParameter = "department=\(selectedDep)";
request.httpBody = postParameter.data(using: String.Encoding.utf8)
// Here I create and send dataTask
let task = URLSession.shared.dataTask(with: request)
{ (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
if(error != nil)
{
self.alertMessage(message: (error?.localizedDescription)!)
return
}
// This is supposed to read data from server side and display it
// in Course table view.
self.courses = try! JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSArray
self.tableView.reloadData()
}
}
task.resume()
}

In Swift, tableView data loaded from JSON only loads 80% of the time

I'm populating my tableView with JSON data, most of the time the data shows but for some strange reason other times it doesn't. I tested the JSON data in Chrome and the info is there. I also made print statements to print the info after it has downloaded and it appears to download correctly. I can't figure out why 80% of the time the data populates the tableView correctly and 20% of the time it doesn't. Here is a sample of my code, there are many more cells but I shortened it to 2 for this example:
var task : NSURLSessionTask?
var newURL : String?
var bannerArray: [String] = []
var overViewArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
getJSON(newURL!)
}
func getJSON (urlString: String) {
let url = NSURL(string: urlString)!
let session = NSURLSession.sharedSession()
task = session.dataTaskWithURL(url) {(data, response, error) in
dispatch_async(dispatch_get_main_queue()) {
if (error == nil) {
self.updateDetailShowInfo(data)
}
else {
"Not getting JSON"
}
}
}
task!.resume()
}
func updateDetailShowInfo (data: NSData!) {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
guard let banner = jsonResult["banner"] as? String,
let overview = jsonResult["overview"] as? String
else { return }
_ = ""
print(overview)
bannerArray.append(banner)
overViewArray.append(overview)
}
catch {
print("It ain't working")
}
self.DetailTvTableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0: return bannerArray.count
case 1: return overViewArray.count
default: fatalError("Unknown Selection")
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("bannerCell", forIndexPath: indexPath) as! BannerCell
cell.bannerImage.sd_setImageWithURL(NSURL(string: bannerArray[indexPath.row]))
self.DetailTvTableView.rowHeight = 100
DetailTvTableView.allowsSelection = false
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("overviewCell", forIndexPath: indexPath) as! OverviewCell
let overViewText = overViewArray[indexPath.row]
if overViewText != "" {
cell.overView.text = overViewText
} else {
cell.overView.text = "N/A"
}
self.DetailTvTableView.rowHeight = 200
print(overViewArray[indexPath.row])
return cell
default: ""
}
return cell
}
I'm just doing this off the web. And I think there are some errors. You need to debug them yourself.
Your understanding of fetching the JSON and GCD is totally wrong. I believe these codes you got somewhere off the web. Go read up what is dispatch_async.
Basically, you need to create session to fetch JSON data, which you have done it correctly, however, within the NSJSONSerialization, you need to store them in a variable and append it to your array. This is fetched asynchronously. Your dispatch_async will reload data serially.
func getJSON (urlString: String) {
let url = NSURL(string: urlString)!
let session = NSURLSession.sharedSession()
task = session.dataTaskWithURL(url) {(data, response, error) in
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
guard let banner = jsonResult["banner"] as? String,
let overview = jsonResult["overview"] as? String
bannerArray.append(banner)
overViewArray.append(overview)
} dispatch_async(dispatch_get_main_queue()) {
if (error == nil) {
self.DetailTvTableView.reloadData()
}
else {
"Not getting JSON"
}
}
catch {
print("It ain't working")
}
}
}
task!.resume()
}

Resources