variable used before being initialized
This is because of the way of initialising variables in Swift, In Swift Class each property need some default value before being used.
Class initialisation in Swift is a two-phase process. In the first
phase, each stored property is assigned an initial value by the class
that introduced it. Once the initial state for every stored property
has been determined, the second phase begins, and each class is given
the opportunity to customize its stored properties further before the
new instance is considered ready for use.
Try changing your code as below:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController = segue.destinationViewController as! SecondTableViewController
var secondArrays : SecondTableData?
if let indexPath = self.tableView.indexPathForSelectedRow {
secondArrays = secondArrayData[indexPath.row]
//Here you're making sure that the secondArrays would must have a value
destViewController.secondArray = secondArrays.secondTitle
}
}
False error? `Variable used before being initialized` DURING initialization in init()
This code:
@State var greeting: String
Creates a backing variable behind the scenes:
let _greeting: State<String>
If you want to initialize it yourself in init(), you can do:
init() {
_greeting = new State<String>(initialValue: "Hello, World!")
}
but since you have a constant, it is simpler to set it like this:
@State var greeting: String = "Hello, World!"
The 3rd variant works, because without @State there's no magic.
The 1st option doesn't work, because the code gets translated to:
init() {
self._greeting.wrappedValue = "Hello, World!"
}
and _greeting
is not initialized at this point (no initialValue is specified). Yes, the error is misleading.
I don't know why the 2nd version works. No initialValue is specified, and the String has no implicit default value. Maybe this is a new feature of iOS 15 SwiftUI that should work, but doesn't work in all cases due to some limitations?
P.S. There is something like "preinit": all properties that are assigned with some expressions like length = Measurement<UnitLength>(...)
are run there before init, but there's no access to it, it is internal.
Swift: Variable used before being initialized]
You need to initialise state itself, like
_entryData = State(initialValue:
EditEntryData(info: entry.infos,
value: String(value), date: entry.date, iOwe: iOwe))
Another Variable '__' used before being initialized question
That variable is a little different than normal because of its @State
property wrapper. To initialize it here without that error, you need to do this:
self._string = State(initialValue: "Why doesn't this work????")
The _
lets you access string
without the property wrapper. In fact, you're already doing this on the line above with your Binding
with a similar strategy.
On your second example, string
already has a default value of ""
, so the compiler isn't worried about it not being set yet.
Variable used before being initialized error (Swift)
Just do the following:
@State var item: Item
init(item: Item) {
_item = State(initialValue: item)
}
You can access all of the things you may need:
item
$item.name
(equivalent to when you had$name
, same for other below)$item.imageData
$item.timestamp
Also, if you don't need to pass anything else in, you can also get rid of the initializer because it is an inferred memberwise intializer.
Reason for the error you were having:
self.item
doesn't exist yet. You set the @State
with _item
, and that will make the item
and $item
variables.
We can see this because seeing the definition of State
shows the following:
public var wrappedValue: Value { get nonmutating set } // Normal value
/* ... */
public var projectedValue: Binding<Value> { get } // Binding value
So since you can't access self.item
because _item
hasn't been initialized yet, you get the error. That's why we set _item
using State(initialValue:)
.
Variable 'varname' used before being initialized in SwiftUI]
This should work:
init(_ test: Test2) {
_t = State(initialValue: test) // Variable 'self.t' used before being initialized
}
@State is a property wrapper, so you need to assign value to the underlying property, thus _ .
Variable used by function before being initialized
Without a big refactor, the quickest changes may be explicitly passing the Binding
to cityName
through the views and to the UserLocationManager
. That might look like this:
struct ContentView: View {
@State var cityName:String = ""
@State var temp:Double = 0
@State var condition:String = ""
var body: some View {
VStack{
UserLocatonButtonView(cityName: $cityName)
WeatherInfo(cityName: $cityName, temp: $temp, condition: $condition)
}
}
}
struct WeatherInfo: View {
@Binding var cityName: String
@Binding var temp: Double
@Binding var condition: String
var body: some View {
HStack {
Text(cityName.capitalized)
.padding()
.font(.title)
Text(String(format: "%.1f *C", temp))
.padding()
.font(.title)
Text(condition)
}
.frame(maxWidth: 400)
.background(Color.black.opacity(0.1))
}
}
struct UserLocatonButtonView: View {
@StateObject private var locationManager : UserLocationManager
init(cityName: Binding<String>) {
_locationManager = StateObject(wrappedValue: UserLocationManager(cityName: cityName))
}
var body: some View {
VStack {
if let location = locationManager.location {
Text("Your location: \(location.coordinate.latitude), \(location.coordinate.longitude)")
}
LocationButton(.currentLocation) {
locationManager.requestAllowOnceLocationPermission()
}
.foregroundColor(.white)
.cornerRadius(8)
.labelStyle(.titleAndIcon)
.symbolVariant(.fill)
.tint(Color.black.opacity(0.3))
}
}
}
final class UserLocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
var cityName : Binding<String>
@Published var location = CLLocation()
let locationManager = CLLocationManager()
init(cityName: Binding<String>) {
self.cityName = cityName
super.init()
locationManager.delegate = self
}
// Request location once
func requestAllowOnceLocationPermission() {
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if there are not locations
guard let latestLocation = locations.last else {
// show an error
return
}
// If location is updated
DispatchQueue.main.async {
let geocoder = CLGeocoder()
self.location = CLLocation(latitude: latestLocation.coordinate.latitude, longitude: latestLocation.coordinate.longitude)
//self.location = latestLocation.coordinate
print("\(latestLocation.coordinate.latitude), \(latestLocation.coordinate.longitude)")
geocoder.reverseGeocodeLocation(self.location) { (placemarks, error) in
self.processResponse(withPlacemarks: placemarks, error: error)
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("\(self.location.coordinate.latitude), \(self.location.coordinate.longitude)")
print(error.localizedDescription)
}
func processResponse(withPlacemarks placemarks: [CLPlacemark]?, error: Error?) {
if let error = error {
print("Unable to Reverse Geocode Location (\(error))")
//locationLabel.text = "Unable to Find Address for Location"
} else {
if let placemarks = placemarks, let placemark = placemarks.first {
//locationLabel.text = placemark.compactAddress
cityName.wrappedValue = placemark.locality!
} else {
print("No matching address found")
//locationLabel.text = "No Matching Addresses Found"
}
}
}
}
That being said, I think a much cleaner solution would be moving the shared state to be owned by the parent view a model and @Published
property. Also, perhaps it's just a result of your minimal example, but you only need to use Binding
s when you need two-way communication. So, as it stands, your WeatherInfo
doesn't need Binding
s at all. Once such refactor might look like this:
struct Model {
var cityName : String
var temp: Double
var condition: String
}
struct ContentView: View {
@StateObject private var manager = UserLocationWeatherManager()
var body: some View {
VStack{
UserLocatonButtonView(manager: manager)
WeatherInfo(cityName: manager.model.cityName,
temp: manager.model.temp,
condition: manager.model.condition)
}
}
}
struct WeatherInfo: View {
var cityName: String
var temp: Double
var condition: String
var body: some View {
HStack {
Text(cityName.capitalized)
.padding()
.font(.title)
Text(String(format: "%.1f *C", temp))
.padding()
.font(.title)
Text(condition)
}
.frame(maxWidth: 400)
.background(Color.black.opacity(0.1))
}
}
struct UserLocatonButtonView: View {
@ObservedObject var manager : UserLocationWeatherManager
var body: some View {
VStack {
if let location = manager.location {
Text("Your location: \(location.coordinate.latitude), \(location.coordinate.longitude)")
}
LocationButton(.currentLocation) {
manager.requestAllowOnceLocationPermission()
}
.foregroundColor(.white)
.cornerRadius(8)
.labelStyle(.titleAndIcon)
.symbolVariant(.fill)
.tint(Color.black.opacity(0.3))
}
}
}
final class UserLocationWeatherManager: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var model = Model(cityName: "", temp: 0, condition: "")
@Published var location = CLLocation()
let locationManager = CLLocationManager()
override init() {
super.init()
locationManager.delegate = self
}
// Request location once
func requestAllowOnceLocationPermission() {
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if there are not locations
guard let latestLocation = locations.last else {
// show an error
return
}
// If location is updated
DispatchQueue.main.async {
let geocoder = CLGeocoder()
self.location = CLLocation(latitude: latestLocation.coordinate.latitude, longitude: latestLocation.coordinate.longitude)
//self.location = latestLocation.coordinate
print("\(latestLocation.coordinate.latitude), \(latestLocation.coordinate.longitude)")
geocoder.reverseGeocodeLocation(self.location) { (placemarks, error) in
self.processResponse(withPlacemarks: placemarks, error: error)
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("\(self.location.coordinate.latitude), \(self.location.coordinate.longitude)")
print(error.localizedDescription)
}
func processResponse(withPlacemarks placemarks: [CLPlacemark]?, error: Error?) {
if let error = error {
print("Unable to Reverse Geocode Location (\(error))")
//locationLabel.text = "Unable to Find Address for Location"
} else {
if let placemarks = placemarks, let placemark = placemarks.first {
//locationLabel.text = placemark.compactAddress
self.model.cityName = placemark.locality!
} else {
print("No matching address found")
//locationLabel.text = "No Matching Addresses Found"
}
}
}
}
Why do I get a Variable used before being initialized error on the line that I initialise the variable in Swift?
Swift has this behaviour because of two phase initialisation. From Apple's Swift book:
Class initialization in Swift is a two-phase process. In the first
phase, each stored property is assigned an initial value by the class
that introduced it. Once the initial state for every stored property
has been determined, the second phase begins, and each class is given
the opportunity to customize its stored properties further before the
new instance is considered ready for use.
Classes need some kind of default value before the first phase ends. Customising values is part of the second phase.
Objective-C didn't have this behaviour because it could always give 0
as default for primitives and nil
for objects, but in Swift there is no mechanism to give such a default value.
Related Topics
No Such File and Directory Found Xcode 7
Alamofire:How to Handle Errors Globally
What Happens If My Distribution Certificate Expires
Using iOS Gamekit's "Bluetooth Bonjour" with Other Platforms
Alternative Ways to Push View Controllers with Storyboard Programmatically
Xcode 7 Uitests with Localized Ui
How to Programmatically Check Support of 'Face Id' and 'Touch Id'
Where Does the Indexpath of Dequeuereusablecellwithidentifier:Forindexpath: Get Used
Xcode 9.2 Upload to App Store Fails with Description Length and Invalid Toolchain Errors
Return Lighter Color from Skcolor Using Hsl Lightness Factor
Disable the Interactive Dismissal of Presented View Controller
How to Set Image as a Title to Uinavigationbar
Present Uialertcontroller on Top of Everything Regardless of the View Hierarchy
Xcode Won't Let to Build for Device After Denying Codesign to Access Keychain