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:
sampleText
is assigned a valuebooksArray
is assigned a valueaBook
is not assigned since islazy
. Waits for access in order to be assigned a value.ContentView
is initalized- You access
aBook
in the body aBook
tries to assign a value, but becauseContentView
is 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.