As a newbie in the Swift programming language as well as programming for iOS, I am trying to make a very simple application.
I just want to create a different class who download the data from a website (parse and get what I want) and finally show it them to the user. Why does this in Swift seem so difficult? Is it or not?
In the end I have managed to download ( with URLSession.shared.dataTask ), parse ( with SwiftSoup ) and keep the data who I want in a swift class that I designed and is responsible for this process. So, I have my class "Announcements", in which I have implemented various methods to get what I want. This class works.
Below is the code of responsible class for downloading and parsing the data:
import Foundation
import SwiftSoup
class Announcements
{
private var annTitles = [String]()
// https://stackoverflow.com/questions/25407447/getting-data-from-a-website-in-swift
// https://stackoverflow.com/questions/24016142/how-to-make-an-http-request-in-swift
private func getHTML(aURL: String, completion: ( (String) -> (Void) )?)
{
let url = URL(string: aURL)!
let task = URLSession.shared.dataTask(with: url)
{
(data, response, error) in
guard let data = data else { return }
// print(String(data: data, encoding: .utf8)!)
let tempHTML = String(data: data, encoding: .utf8)!
completion?(tempHTML)
}
task.resume()
}
public func getAnnouncements()
{
self.getHTML(aURL: "https://www.my.site/news.php")
{ result in
if result.isEmpty
{
print("Announcements could not be downloaded!")
}
else
{
print("Successful download of announcements.")
self.parseHTML(html: result)
}
// Default
}
}
private func parseHTML(html : String)
{
do
{
let doc: Document = try SwiftSoup.parse( html )
let table: Elements = try doc.getElementsByClass( "table" )
for tr in try! table.select("tr")[1...100]
{
let td : Elements = try tr.select("td")
self.annTitles.append( try td[0].text() )
}
// self.viewData()
}
catch Exception.Error(let type, let message)
{
print(type)
print(message)
}
catch
{
print("SwiftSoup parsing data error!")
}
print("All good!")
}
public func getTitles() -> [String]
{
return self.annTitles
}
public func viewData()
{
for i in 0...99
{
print( self.annTitles[i] )
}
}
}
How can I call it and get the data it holds the above class in the main TableViewController?
I want a simple list on the user's screen to display a title in each cell.
Below is the code from (GUI) UITableViewController :
//
// TableViewController.swift
// uoiAnnouncements
//
import UIKit
class TableViewController: UITableViewController {
var announcements : Announcements?
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
self.announcements = Announcements()
self.announcements?.getAnnouncements()
self.announcements?.viewData()
}
// MARK: - Table view data source
// override func numberOfSections(in tableView: UITableView) -> Int {
// // #warning Incomplete implementation, return the number of sections
// return 0
// }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 100 // Const because only 100 are initially announcements.
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "announcementCell", for: indexPath)
// Configure the cell...
self.reloadInputViews()
cell.textLabel?.text = self.announcements?.getTitles()[indexPath.row] // <---- Here is the problem!
// ** Announcements not downloaded yet ** !
return cell
}
}
The problem is how downloading of announcements is an asynchronous process that doesn't run on the main thread - and I don't know when it ends -!
How can I tell the main "window"/screen/TableViewController to wait?
Can I know when the data has been downloaded?
Can I send a signal, put a semaphore or something?
Thank you very much for your time!