I followed an youtube tutorial(since 2020) and I got a problem that I can't find a solution. I just want to show my a quote, randomized, in a label. Everytime user press the button, the text label is changed with another quote from json.
This is my VC where I want to display data
class ViewController: UIViewController {
@IBOutlet weak var quoteView: UITextView!
var result: Result?
override func viewDidLoad() {
super.viewDidLoad()
quoteView.text = "You only live once, but if you do it right, once is enough. — Mae West"
parsejson()
}
@IBAction func quoteTriggered(_ sender: Any) {
quoteView.text = result?.data //Cannot assign value of type '[ResultItem]?' to type 'String?'
}
private func parsejson() {
guard let path = Bundle.main.path(forResource: "data", ofType: "json") else { return }
let url = URL(fileURLWithPath: path)
var result: Result?
do {
let jsonData = try! Data(contentsOf: url)
result = try JSONDecoder().decode(Result.self, from: jsonData)
if let result = result {
print(result)
} else {
print("Failed to pase")
}
}
catch {
print("Error \(error)")
}
}
}
struct Result: Codable {
let data: [ResultItem]
}
struct ResultItem: Codable {
let quote: String?
}
And my JSON file is this
{
"quote" : "\"Thegreatest glory in living lies not in never falling, but in rising every time we fall. -Nelson Mandela\"": {},
"quote" : "\"Theway to get started is to quit talking and begin doing. -Walt Disney\"": {},
"quote" : "\"Ifyou look at what you have in life, you'll always have more. If you look at what you don't have in life, you'll never have enough. -Oprah Winfrey\"": {},
"quote" : "\"Ifyou set your goals ridiculously high and it's a failure, you will fail above everyone else's success. -James Cameron\"": {},
"quote" : "\"Lifeis what happens when you're busy making other plans. -John Lennon\"": {},
"quote" : "\"Spreadlove everywhere you go. Let no one ever come to you without leaving happier. -Mother Teresa\"": {},
"quote" : "\"Don'tjudge each day by the harvest you reap but by the seeds that you plant. -Robert Louis Stevenson\"": {},
"quote" : "\"Tellme and I forget. Teach me and I remember. Involve me and I learn. -Benjamin Franklin\"": {},
"quote" : "\"Thefuture belongs to those who believe in the beauty of their dreams.\" -Eleanor Roosevelt\"": {},
"quote" : "\"Iflife were predictable it would cease to be life and be without flavor.\" -Eleanor Roosevelt\"": {},
"quote" : "\"\"Lifeis a succession of lessons which must be lived to be understood.\" -Ralph Waldo Emerson\"": {},
"quote" : "\"\"Youwill face many defeats in life, but never let yourself be defeated.\" -Maya Angelou\"": {},
"quote" : "\"\"Theonly impossible journey is the one you never begin.\" -Tony Robbins\"": {},
"quote" : "\"\"Onlya life lived for others is a life worthwhile.\" -Albert Einstein\"": {},
"quote" : "\"\"Thegreatest glory in living lies not in never falling, but in rising every time we fall.\" -Nelson Mandela\"": {},
"quote" : "\"\"Lifeis really simple, but we insist on making it complicated.\" -Confucius\"": {},
"quote" : "\"Lifeis a long lesson in humility. -James M. Barrie\"": {},
"quote" : "\"Lovethe life you live. Live the life you love. -Bob Marley\"": {},
"quote" : "\"Manyof life's failures are people who did not realize how close they were to success when they gave up. -Thomas A. Edison\"": {},
"quote" : "\"\"Life is made of ever so many partings welded together.\" -Charles Dickens\"": {}
}
CodePudding user response:
Right now, as the error says, you're trying to assign an array of ResultItem
to text
, which is a String?
Since you want a random item, you can use randomElement()
to choose a random item from that array. At that point, you'll need to grab the quote
(which is a String
) from that element.
quoteView.text = result?.data.randomElement()?.quote
CodePudding user response:
Consider this solution:
Instead of storing the Result
object store the collection of ResultItem
the Container type is not needed as it stores only the data property.
Also don´t use try!
especially not in a do/catch
block. That check for nil is also uneccessary and will hide errors that occur while decoding.
class ViewController: UIViewController {
@IBOutlet weak var quoteView: UITextView!
var results: [ResultItem] = []
override func viewDidLoad() {
super.viewDidLoad()
quoteView.text = "You only live once, but if you do it right, once is enough. — Mae West"
parsejson()
}
@IBAction func quoteTriggered(_ sender: Any) {
//access a random element of the collection
quoteView.text = results.randomElement()?.quote ?? "error"
}
private func parsejson() {
guard let path = Bundle.main.path(forResource: "data", ofType: "json") else { return }
let url = URL(fileURLWithPath: path)
do {
let jsonData = try Data(contentsOf: url)
let result = try JSONDecoder().decode(Result.self, from: jsonData)
self.results = result.data
}
catch {
print("Error \(error)")
}
}
}
Edit:
Regarding your comment about seeing "error" after pressing the button. The JSON you provided is not valid JSON. Even more this does not fit the Model structs you provided in your question. Therefore the decoding fails and your results
collection remains empty. As there are no entries the .randomElement
method returns nil
and the default value "error" is used.
A valid structure would be this:
{
"data": [
{"quote" : "\"Thegreatest glory in living lies not in never falling, but in rising every time we fall. -Nelson Mandela\""},
{"quote" : "\"Theway to get started is to quit talking and begin doing. -Walt Disney\""},
{"quote" : "\"Ifyou look at what you have in life, you'll always have more. If you look at what you don't have in life, you'll never have enough. -Oprah Winfrey\""}
]
}