Cannot Use Instance Member Within Property Initializer

Cannot use instance member within property initializer

So if we decode the error message you can figure out whats wrong. It says property initializers run before self is available so we need to adjust what we're doing since our property depends on bounds which belongs to self. Lets try a lazy variable. You can't use bounds in a let because it doesn't exist when that property is created because it belongs to self. So at init self isn't complete yet. But if you use a lazy var, then self and its property bounds will be ready by the time you need it.

lazy var arrowPath = UIBezierPath.bezierPathWithArrowFromPoint(startPoint: CGPoint(x: self.bounds.size.width/2,y: self.bounds.size.height/3), endPoint: CGPoint(x: self.bounds.size.width/2, y: self.bounds.size.height/3*2), tailWidth: 8, headWidth: 24, headLength: 18)

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))
}
}

Cannot use instance member within property initializer; property initializers run before 'self' is available

If you want to use one class property (or in this case two) to initialize another class property, you need a way to make sure the required properties have already been set.

If you mark dateManager as lazy it won't be initialized until it's accessed for the first time. By the time it can be accessed, self will be fully available so the compiler should be happy.

lazy var dateManager = DateManager(years: datePicker, time: timePicker)

Xcode error: Cannot use instance member 'selectedWateredDate' within property initializer; property initializers run before 'self' is available

Change the let property to a computed variable.

var dateInterval : DateInterval { DateInterval(start: selectedWateredDate, end: waterMeAgainIn)}

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 Maps - Cannot use instance member within property initializer; property initializers run before 'self' is available

I was close in the final edit, but I needed to assign the value _region - not the prefixed underscore. It looks like this is a private setter which is why you need to wrap the value in State. And not forget to use the $ prefix to use the instance variable in the view.

struct PlaceDetail: View {
let place: Place

@State var region: MKCoordinateRegion

init(place: Place) {
self.place = place

let region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: place.latitude, longitude: place.longitude),
latitudinalMeters: 750,
longitudinalMeters: 750
)

self._region = State(initialValue: region)
}

var body: some View {
Map(coordinateRegion: $region)
}
}

Cannot use instance member 'generateRandomNumbers' within property initializer; property initializers run before 'self' is available

You are asking var array to receive a "default" value from the function generateRandomNumbers(). The "default" value is set during the initialisation of the instance of your view controller, so before the instance exists, so before the generateRandomNumbers() function exists. The compiler doesn't know how to give a value to array before the instance has finished being created.

A workaround is to set a dummy default value, then change it during initialisation, like this:

@IBOutlet weak var tableView1: UITableView!
var array = [Int]() // This is an empty array, the compiler can create it before the generateRandomNumbers() is available
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView1.delegate = self
tableView1.dataSource = self
...

array = generateRandomNumbers(size: 1000) // Now that all variables are initialised, you can change their values


Related Topics



Leave a reply



Submit