Property initializers run before 'self' is available
As correctly pointed out by vadian you should create an init
in such scenarios:
class MyOwn {
let myUser: User
var life: Int
init() {
self.myUser = User(name: "John", age: 100)
self.life = myUser.age
}
}
You can't provide a default value for a stored property that depends on another instance property.
Cannot use instance member 'service' within property initializer; property initializers run before 'self' is available
Basically, what the compiler is saying is that "I'm still creating the instance of your DetailCardView
, I don't know yet what is the value of service
so I can't use it in the region
".
The solution is to pass the service
to a constant that will be used to initialise both properties. You need to create an initializer for your View where you pass this constant.
Here's how it looks:
let service: gService
// Rather than service.longitude and service.latitude, use a dummy value, like 0.0
// Recommended this var to be private
@State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0), span: MKCoordinateSpan(latitudeDelta: 0.0033, longitudeDelta: 0.0033))
// Here's your initializer
init(service: gService) {
self.service = service // Use service to initialise self.service
// Use service - and NOT self.service - to initialise region
region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: service.latitude, longitude: service.longitude), span: MKCoordinateSpan(latitudeDelta: 0.0033, longitudeDelta: 0.0033))
}
var body: some View {
... // The rest of your code
Another method you can try is to drop the init()
and set the region
when the view appears, like this:
let service: gService
// Rather than service.longitude and service.latitude, use a dummy value, like 0.0
// Recommended this var to be private
@State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0), span: MKCoordinateSpan(latitudeDelta: 0.0033, longitudeDelta: 0.0033))
var body: some View {
Map(coordinateRegion: $region, annotationItems: [MapPoint(coordinates: CLLocationCoordinate2D(latitude: service.latitude, longitude: service.longitude))]) { location in
MapAnnotation(coordinate: location.coordinates) {
Circle()
.stroke(.red, lineWidth: 3)
.frame(width: 50, height: 50, alignment: .center)
}
.onAppear {
region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: service.latitude, longitude: service.longitude), span: MKCoordinateSpan(latitudeDelta: 0.0033, longitudeDelta: 0.0033))
}
}
SwiftUI Cannot use instance member 'numberOfDevice' within property initializer; property initializers run before 'self' is available error
You can use read-only computed property with short-hand.
var text: String {
return (BluetoothManager.peripheralArray[numberOfDevice]?.name)!
}
Cannot use instance member 'getA' within property initializer; property initializers run before 'self' is available
Property initializer run before self
is available.
The solution is to lazy initialize
the property:
class A {
lazy var asd: String = getA()
func getA() -> String {
return "A"
}
}
That will initialize the property first time you are trying to use it.
Cannot use instance member 'videoName' within property initializer; property initializers run before 'self' is available
Option 1:
Create an initializer for your View
that creates your @State
initial value:
struct ExercisingSessionView: View {
let exerciseName: String
let videoName: String
@State var player : AVPlayer
@State var isplaying = false
@State var showcontrols = false
init(exerciseName: String, videoName: String) {
self.exerciseName = exerciseName
self.videoName = videoName
self._player = State(initialValue: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: videoName, ofType: "mov")!)))
}
var body: some View {
CustomVideoPlayer(player: $player)
.frame(width: 390, height: 219)
.onTapGesture {
self.showcontrols = true
}
}
}
The downside to this is if ExercisingSessionView
gets initialized often (even if it doesn't get actually re-rendered to the view hierarchy), you're doing heavy lifting inside init
, which is generally a pretty bad idea for performance.
Option 2:
Declare player
as optional and load the initial value in onAppear
:
struct ExercisingSessionView: View {
let exerciseName: String
let videoName: String
@State var player : AVPlayer?
@State var isplaying = false
@State var showcontrols = false
var body: some View {
Group {
if let player = player {
CustomVideoPlayer(player: player)
.frame(width: 390, height: 219)
.onTapGesture {
self.showcontrols = true
}
}
}.onAppear {
player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: videoName, ofType: "mov")!))
}
}
}
struct CustomVideoPlayer : UIViewControllerRepresentable {
var player: AVPlayer
func makeUIViewController(context: UIViewControllerRepresentableContext<CustomVideoPlayer>) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.player = player
controller.showsPlaybackControls = false
return controller
}
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<CustomVideoPlayer>) {
}
}
This avoids the issue in option 1 because onAppear
will only be called once.
Note that here, I've made player
inside CustomVideoPlayer
a regular, non-binding property -- because AVPlayer
is an class, passed by reference, there's no reason to have a @Binding
with it.
SwiftUI: Property initializers run before 'self' is available in @AppStorage use
You can't refer to $currency
when you define cur
. This is a limitation of Swift. It obvious to you that currency has a value already, but Swift won't let you use it until after the initializer is done setting up self. This has nothing to do with AppStorage -- it's a rule that property initializers cannot refer to other (non-static) properties.
So, this
@State private var currency = "$"
@AppStorage("cur") var cur = "\($currency)"
Could be
@State private var currency = "$"
@AppStorage("cur") var cur = "$" // set it to the same value
or
private static let dollar = "$"
@State private var currency = SettingsView.dollar
@AppStorage("cur") var cur = SettingsView.dollar
Related Topics
What Is the "Some" Keyword in Swift(Ui)
Input from the Keyboard in Command Line Application
How to Stop a Dispatchworkitem in Gcd
Differences in Nsdatecomponents Syntax
Real Time Nstask Output to Nstextview With Swift
What Does It Mean That String and Character Comparisons in Swift Are Not Locale-Sensitive
How to Get the Count of a Swift Enum
Dyld: Library Not Loaded: @Rpath/Libswift_Stdlib_Core.Dylib
Swift Protocol With "Where Self" Clause
The "++" and "--" Operators Have Been Deprecated Xcode 7.3
Send Data from Tableview to Detailview Swift
Swift Protocol Extension Method Is Called Instead of Method Implemented in Subclass
What Is the Point of Having Two Different Names For the Same Parameter