I am trying to load the UItable with some data from the external database. I am able to print the required data in the output panel but cant get the data on the tableview. How can I fix this?
Code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//let myarray = ["item1", "item2", "item3"]
var group = [Group]()
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://www.myurl/myfile.php")
let task = URLSession.shared.dataTask(with: url! as URL) { data, response, error in
guard let data = data, error == nil else { return }
print(NSString(data: data, encoding: String.Encoding.utf8.rawValue))
}
task.resume()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableview.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return myarray.count
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "groupCell", for: indexPath) as! UITableViewCell
// cell.textLabel?.text = myarray[indexPath.item]
return cell
}
}
Tableview reload before receiving data. You need to reload table view after completing task.
let task = URLSession.shared.dataTask(with: url! as URL) { data, response, error in
guard let data = data, error == nil else { return }
print(NSString(data: data, encoding: String.Encoding.utf8.rawValue))
//Store into your array depend on response.
DispatchQueue.main.async() {
self.tableView.reloadData()
} } task.resume()
Related
I have an API of list of countries and I'm trying to get access to the data fetched from the API outside its function.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var apiData:[Countries] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tableView.delegate = self
self.tableView.dataSource = self
fetchAPI()
}
func fetchAPI() {
let apiEndPoint = "https://restcountries.com/v2/all"
guard let url = URL(string: apiEndPoint) else {
print("Could not convert API endpoint to url object")
return
}
URLSession.shared.dataTask(with: url) { (data,response, error) in
if let err = error {
print("Error occured while fetching the data")
print(err)
return
}
if let jsonData = data {
do {
let decoder = JSONDecoder()
let decodedItem:[Countries] = try decoder.decode([Countries].self, from: jsonData)
DispatchQueue.main.async {
self.apiData = decodedItem
}
} catch let error {
print("An error occured during JSON decoding")
print(error)
}
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as UITableViewCell
return cell
}
}
I tried defining an apiData variable outside the scope and passing the data to it but when I try to use it in my tableView it is empty.
What am I doing wrong?
Assuming that no error occurs in your fetchAPI function, after getting response and passing the data to your apiData variable, you should reload tableView data:
self.tableView.reloadData()
And in numberOfRowsInSection function:
return apiData.count
Then you should configure each cell to show your data inside cellForRowAt function.
I am trying to get my JSON data to display in a tableview but cant get it to work. I have managed to display some data in text views but cannot get the data into the tableview
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
final let url = URL(string: "http://**.***.**.**:*****/userconfig")
private var users = [User]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
downloadJSON()
}
func downloadJSON() {
guard let downloadURL = url else { return }
URLSession.shared.dataTask(with: downloadURL) { (data, urlResponse, error) in
guard let data = data, error == nil, urlResponse != nil else {
print("Trouble!")
return
}
print("Success!")
do {
let decoder = JSONDecoder()
let downloadedComms = try decoder.decode(Users.self, from: data)
self.users = downloadedComms.users
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch {
print("Bad!")
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "CommCell") as? CommCell else { return UITableViewCell() }
cell.nameLbl.text = users[indexPath.row].username
cell.DOBLbl.text = users[indexPath.row].online
return cell
}
}
Replace This with your viewDidLoad method. You didnt set your delegete and dataSource.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
downloadJSON()
}
thanks for all your helpfull comments. It turns out that because I was not putting all the JSON fields in my class I needed to make the ones I was including optional.
class Users: Codable {
let users: [User]
init(users: [User]) {
self.users = users
}
}
class User: Codable {
let username: String?
let online: String?
let image: String?
init(username: String, online: String, image: String) {
self.username = username
self.online = online
self.image = image
}
I am using an endpoint that returns a JSON as response. The problem is response json is a huge data to process for me. From that I want to show all the Surah(englishName) name to display in the tableview. I tried my best as a new bee to iOS development. Please take a look at my snippet and let me know where i am doing wrong.
my Json data here:
ViewController code:
var surahName = [Surah]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: JSON parse
func parseJSON() {
let url = URL(string: "https://api.alquran.cloud/v1/quran/ar.alafasy")
guard url != nil else{
print("URL Founr Nill")
return
}
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil && data != nil{
do{
self.surahName = try JSONDecoder().decode([Surah].self, from: data!)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print(error)
}
}
}.resume()
}
//MARK: Tableview delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return surahName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:QuranAudioCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! QuranAudioCell
let arrdata = surahName[indexPath.section].data.surahs
cell.nameLbl.text = arrdata[indexPath.row].englishName
return cell
}
Problem is its not printing anything in the tablview.
Change first line as
var surahNames = [EnglishName]()
Inside do-catch block change
self.surahName = try JSONDecoder().decode([Surah].self, from: data!)
into
let response = try JSONDecoder().decode(Surah.self, from: data!)
self.surahName = response.data.surahs
Now inside cellForRowAtIndexPath do this
let surah = surahName[indexPath.row]
cell.nameLbl.text = surah.englishName
I can't figure out why the cells don't return with data.
I can parse normally using the Decodable, which means that is working.
I've been trying all the methods I find without success.
struct MuscleGroup: Decodable {
let ExcerciseID: String
let description: String
let excerciseName: String
let muscleGroup: String
}
class ExerciseListViewController: UITableViewController {
var muscleGroup = [MuscleGroup]()
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return muscleGroup.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExerciseList", for: indexPath) as! ExcerciseList
let muscle = muscleGroup[indexPath.row]
cell.textLabel!.text = muscle.excerciseName
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(self.muscleGroup[indexPath.row])
tableView.deselectRow(at: indexPath, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
getJson()
}
func getJson(){
guard let url = URL(string: "https://jsonurl") else { return }
let session = URLSession.shared
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do {
let muscles = try JSONDecoder().decode([MuscleGroup].self, from: data)
for muscle in muscles {
let muscleGroup = muscle.excerciseName
print(muscleGroup)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
} catch {
print(error)
}
}
}.resume()
}
If I change the var muscleGroup = String to ["Chest", "Back", "Abdominals","Arms", "Legs"] it returns correctly.
Also, the print result on the console returns all the data that needs to be on the Table View.
What am I doing wrong?
As you probably want to use the entire struct
Replace
var muscleGroup = [String]()
with
var muscleGroups = [MuscleGroup]()
Replace
let muscles = try JSONDecoder().decode([MuscleGroup].self, from: data)
for muscle in muscles {
let muscleGroup = muscle.excerciseName
print(muscleGroup)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
with
self.muscleGroups = try JSONDecoder().decode([MuscleGroup].self, from: data)
DispatchQueue.main.async {
self.tableView.reloadData()
}
Replace
cell.textLabel?.text = self.muscleGroup[indexPath.row]
with
cell.textLabel?.text = self.muscleGroups[indexPath.row].muscleGroup
In your getJson function this line
let muscleGroup = muscle.excerciseName
is creating a new local variable called muscleGroup, change the line to be
self.muscleGroup.append(muscle.excerciseName)
i.e. get rid of the let and append the value to the main array variable
Also move the
DispatchQueue.main.async {
self.tableView.reloadData()
}
to be outside of the for loop of muscles as you are forcing the table to reload for each entry rather than when you are finished
I am new to Swift, and am trying to create a table that reads JSON data from my website. I followed some tutorials, and was able to get my code to work with a table controller. Now I'm trying to use a view controller with a table view inside, so I can have more customization. My problem is, I can't get the data to actually show up when I try to use my new code.
This is what I have in my viewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var TableData:Array< String > = Array < String >()
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.stevenbunting.org/Alliris/service.php")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let countries_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let country_obj = countries_list[i] as? NSDictionary
{
if let country_name = country_obj["user"] as? String
{
if let country_code = country_obj["friendlist"] as? String
{
TableData.append(country_name + " [" + country_code + "]")
}
}
}
}
}
DispatchQueue.main.async(execute: {self.do_table_refresh()
})
}
func do_table_refresh()
{
self.tableView.reloadData()
}
}
Probably you didn't set the tableView's dataSource. To do this, implement the UITableViewDataSource-protocol in the ViewController-class and set the tableView's dataSource-property to self in the viewDidLoad(), for example:
class ViewController: UIViewController, UITableViewDataSource {
// ...
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
// ...
}
//...
}
Oh, and don't forget about the Apple Transport Security-settings, otherwise you won't see anything as iOS doesn't allow HTTP anymore, you have use HTTPS. The right way to handle this is to get an SSL-Certificate for your domain.
The quick'n'dirty and absolutely not recommended way is to disable ATS or to set an exception for certain, trustworthy domains.