property initializers run before 'self' is available

hi i saw the tutorial named

"Loading a specific kind of Codable data – Moonshot SwiftUI Tutorial 5/10"

youtube.com/watch?v=PG_OHOEPx2I&ab_channel=PaulHudson

and it worked perfectly,
but when i tried to do the same thing only without the extension,
i get this error "Cannot use instance member 'decode' within property initializer; property initializers run before 'self' is available".

basically its the same code as on the internet only the function is written in different place (in content view and not inside the bundle extension)!!!

can someone tell me y it happens and how to fix this?

thx in advance.

Code Block swift
struct ContentView: View {
   
  let astronautsJson: [Astronaut] = decode("astronauts.json")
   
  var body: some View {
    Text("\(astronautsJson.count)")
      .padding()
  }
   
  func decode(_ file: String) -> [Astronaut] {
    guard let url = Bundle.main.url(forResource: file, withExtension: nil) else {
      fatalError("Failed to locate \(file) in bundle.")
    }
     
    guard let data = try? Data(contentsOf: url) else {
      fatalError("Failed to load \(file) from bundle.")
    }
     
    let decoder = JSONDecoder()
     
    guard let loaded = try? decoder.decode([Astronaut].self, from: data) else {
      fatalError("Failed to decode \(file) from bundle.")
    }
     
    return loaded
  }
   
}



As you see, in the struct ContentView, you have a declaration of an instance property named astronautsJson, and its initial value (in other words, property initializer) is decode("astronauts.json").

can someone tell me y it happens and how to fix this?

As the error message is clearly stating,
In Swift, you cannot use instance members (neither methods nor properties) within property initializer.

You are trying to use the instance member (in your case, method) decode(_:), so Swift compiler is telling you you cannot.

Using an extension (of other type than ContentView) would be a preferable way, but there may be other ways.
One way is making your decode a type member (static method):
Code Block
struct ContentView: View {
let astronautsJson: [Astronaut] = decode("astronauts.json")
var body: some View {
Text("\(astronautsJson.count)")
.padding()
}
static func decode(_ file: String) -> [Astronaut] {
guard let url = Bundle.main.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
guard let loaded = try? decoder.decode([Astronaut].self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}
return loaded
}
}



By the way, using try? with guard-let is not recommended. You should better find a better video:
Code Block
static func decode(_ file: String) -> [Astronaut] {
guard let url = Bundle.main.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
let data: Data
do {
data = try Data(contentsOf: url)
} catch {
fatalError("Failed to load \(file) from bundle with error: \(error)")
}
let decoder = JSONDecoder()
let loaded: [Astronaut]
do {
loaded = try decoder.decode([Astronaut].self, from: data)
} catch {
fatalError("Failed to decode \(file) from bundle with error: \(error)")
}
return loaded
}

Using do-catch with try (not try?) would make your code a little longer, but you can get more info in case of errors, which may help you finding what is causing the error.
thx very much. but i m still dazzled it works with extension. after all the let astronautJason initializes in the same time in both projects. in 1 it works and in the other it doesn't. go figure!!!!????

i m still dazzled it works with extension.

I guess you do not understand what is instance member.
extension as i know of is a convenience way of writing 1 thing in another place. till now all teachers said it is for a cleaner code. make sense so that astronautJason should intilze in the same time...

(i come from background of theoritical mathematics) believe me if i ask something its really interesting.

answers like "I guess you do not understand what is instance member." don't help. what make me think you don't know the answer for this yourself...

and yes i know how to fix the problem (init, static... you name it) . what is interesting y this problem appears in models that i perceive as identical. thx again
Accepted Answer

answers like "I guess you do not understand what is instance member." don't help.

Then you should have clarified what you do not understand.

When you write an extension of Bundle with the method decode(_:) as in the video,
you can use Bundle.main.decode(...) within the property initializer of astronautsJson.

In this case, decode(_:) is an instance method of Bundle, not of ContentView, so you can use it in the property initializers of instance properties of ContentView.

But in your code, you declare an instance method decode(_:) of ContentView. You cannot use instance members within the property initializer.

This is a restriction of Swift.

Do you understand?
yes. thx you very much. people like you are what makes this forum great!! thx again.

people like you are what makes this forum great!! 

Thanks for your great evaluation. I am very happy if I can help you solve the issues.

property initializers run before 'self' is available
 
 
Q