Im trying to create a small and simple app.
- iOS
- Reads single value from remote JSON file (ie a true/false)
- Displays the value in a UI label on screen
This is the initial idea...but I eventually hope to read the value, and depending on whether true or false...perform some other functionality.
At this stage, just want to read and display it on screen.
Here is what I have so far and it works as far as printing to the log, but not to the screen/UILabel which is my goal.
import UIKit
struct DemoData: Codable {
let title: String
let description: String
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "https://subdomain.domain.com/json/myData.json"
self.loadJson(fromURLString: urlString) { (result) in
switch result {
case .success(let data):
self.parse(jsonData: data)
case .failure(let error):
print(error)
}
}
let labelRect = CGRect(x: 50, y: 100, width: 200, height: 100)
let label = UILabel(frame: labelRect)
label.text = "Description should be here"
label.numberOfLines = 2
view.addSubview(label)
// Do any additional setup after loading the view.
}
private func loadJson(fromURLString urlString: String,
completion: @escaping (Result<Data, Error>) -> Void) {
if let url = URL(string: urlString) {
let urlSession = URLSession(configuration: .default).dataTask(with: url) { (data, response, error) in
if let error = error {
completion(.failure(error))
}
if let data = data {
completion(.success(data))
}
}
urlSession.resume()
}
}
private func parse(jsonData: Data) {
do {
let decodedData = try JSONDecoder().decode(DemoData.self,
from: jsonData)
print("Title: ", decodedData.title)
print("Description: ", decodedData.description)
print("===================================")
} catch {
print("decode error")
}
}
}
Here is the JSON file that is hosted remotely...it will just say true or false, this is what Im using to get it working.
{
"title": "Remote file",
"description": "This is text from the remote JSON file"
}
Its not pretty, but Im hoping to solve small things as I move on with my idea....any help I would be extremely grateful.
Many thanks everyone :)
CodePudding user response:
Currently you're creating the label within the scope of viewDidLoad()
. The value from the JSON response won't be available yet, since it is asynchronously fetched.
If you make the label a class property instead and set its text to decodedData.title
in the same place where you're currently printing out the value, it should populate correctly.
let label = UILabel()
private func parse(jsonData: Data) {
do {
let decodedData = try JSONDecoder().decode(DemoData.self,
from: jsonData)
label.text = decodedData.title
print("Title: ", decodedData.title)
print("Description: ", decodedData.description)
print("===================================")
} catch {
print("decode error")
}
}
P.S.: make sure you add [weak self]
at the beginning of your loadJson(fromURLString: urlString)
completion block in viewDidLoad()
to avoid trying to access self after it's been deallocated :)
CodePudding user response:
First of all declare the label lazily on the top level of the view controller to have a reference
lazy var label : UILabel = {
let labelRect = CGRect(x: 50, y: 100, width: 200, height: 100)
let uiLabel = UILabel(frame: labelRect)
uiLabel.text = "Description should be here"
uiLabel.numberOfLines = 2
return uiLabel
}()
then assign the value after the line to print the description in parse
...
print("===================================")
label.text = decodedData.description
} catch { ...