I couldn't get my the below struct to initialise until I moved it into the body of the View. Can someone explain that to me please? Thanks!
This didn't work:
struct ContentView: View {
var sampleText = "This is sample text"
var booksArray = ["Book 1", "Book 2", "Book 3"]
let aBook = Book(passage: sampleText, books: booksArray)
var body: some View {
ScrollView(.vertical, showsIndicators: false, content: {
VStack {
Text(aBook.passage)
.frame(width: 350, height: .infinity, alignment: .center)
.kerning(1)
}
})
}
}
But this did work:
struct ContentView: View {
var sampleText = "This is sample text"
var booksArray = ["Book 1", "Book 2", "Book 3"]
var body: some View {
let aBook = Book(passage: sampleText, books: booksArray)
ScrollView(.vertical, showsIndicators: false, content: {
VStack {
Text(aBook.passage)
.frame(width: 350, height: .infinity, alignment: .center)
.kerning(1)
}
})
}
}
CodePudding user response:
The error you got from this code reads:
cannot use instance member 'sampleText' within property initializer; property initializers run before 'self' is available
which in plain English means that when aBook is being assigned, self, which is the ContentView is not yet available, so you cannot use sampleText and booksArray to initialize aBook (because it requires all the properties to be initialized - to hold a value).
You might think, ok then I will use lazy to initialize aBook, which means that the assignment of the property will happen after ContentView has finished the initialization - at first access.
lazy var aBook = Book(passage: sampleText, books: booksArray)
but then a new error appears:
Text(aBook.passage) <= cannot use mutating getter on immutable value: 'self' is immutable
wait, what? But I'm not trying to mutate it you might say.
The reality though is that you do mutate ContentView by accessing aBook. Let's illustrate this:
sampleTextis assigned a valuebooksArrayis assigned a valueaBookis not assigned since islazy. Waits for access in order to be assigned a value.ContentViewis initalized- You access
aBookin the body aBooktries to assign a value, but becauseContentViewis a struct (value type - immutable) it needs to make a copy of the whole thing. Which is why you get the error
So, long story short you got a few options:
let aBook = Book(passage: sampleText, books: booksArray)in the body (as you already mention)A computed property:
var aBook: Book { Book(passage: sampleText, books: booksArray) }
or a custom initializer:
init(sampleText: String, booksArray: [String]) {
self.sampleText = sampleText
self.booksArray = booksArray
self.aBook = Book(passage: sampleText, books: booksArray)
}
or even:
let sampleText = "This is sample text"
let booksArray = ["Book 1", "Book 2", "Book 3"]
let aBook: Book
init() {
self.aBook = Book(passage: sampleText, books: booksArray)
}
I hope that this makes sense.
