NEW: Learn to build amazing SwiftUI apps for macOS with my new book! >>

Return from initializer without initializing all stored properties on init

Forums > 100 Days of SwiftUI

Hi guys,

I can sure use the help.

I am making a few view changes to the Converter app as part of day 24 challenges. I am getting the above error on the closing bracket of the MeasurementFormatter init, and cannot get the app to compile.

The changes that I made so far is adding a screen with details of the measurement( the values is stored in a seperate swift file, struct and array, and declared by var info: UnitInfo), and changing the foreground colour of the result textfield.

Am I missing something somewhere(sure I am missing something very stupid) Code is below.

Paul

import SwiftUI

struct ContentView: View {

 @State public var info: UnitInfo

@State private var inputUnit: Dimension = UnitTemperature.celsius
@State private var outputUnit: Dimension = UnitTemperature.fahrenheit
@State private var input = 100.0
@State private var selectedUnits = 0
@FocusState private var keyboardIsFocused: Bool

let formatter: MeasurementFormatter

init () {
    formatter = MeasurementFormatter()
    formatter.unitOptions = .providedUnit
    formatter.unitStyle = .short
} - this is where I get - Return from initializer without initializing all stored properties

let conversions = ["Unit for Measure for Acceleration", "Unit for Measure for Planar Angle and Rotation", "Unit of Measure of Area", "Unit of Measure for Concentration of Mass", "Unit of Measure of Dispersion", "Unit of measure for duration of Time","Unit of Measure for Electric Charge", "Unit of Measure of Electric Current", "Unit of Measure for Electric Potential Difference","Unit of Measure for Electric Resistance","Unit of Measure for Energy","Unit of Measure for Frequency","Unit of Measure for Fuel Efficiency","Unit of Measure for Illuminance", "Unit of Measure for  Quantities of Information","Unit of Measure of Lenght", "Measure of Mass", "Measure of Power", "Unit of Measure for Pressure", "Unit for Measure of Speed", "Unit of Measure for Temperature", "Unit of Measure for Volume"]

let unitTypes = [
    [UnitAcceleration.metersPerSecondSquared, UnitAcceleration.gravity],
    [UnitAngle.degrees, UnitAngle.arcMinutes, UnitAngle.arcSeconds, UnitAngle.radians, UnitAngle.gradians, UnitAngle.revolutions],
    [UnitArea.squareMegameters, UnitArea.squareKilometers, UnitArea.squareCentimeters, UnitArea.squareMillimeters, UnitArea.squareMicrometers, UnitArea.squareNanometers, UnitArea.squareInches, UnitArea.squareFeet, UnitArea.squareYards, UnitArea.squareMiles, UnitArea.acres, UnitArea.ares, UnitArea.hectares],
    [UnitConcentrationMass.gramsPerLiter, UnitConcentrationMass.milligramsPerDeciliter],
    [UnitDispersion.partsPerMillion],
    [UnitDuration.seconds, UnitDuration.minutes, UnitDuration.hours],
    [UnitElectricCharge.coulombs, UnitElectricCharge.megaampereHours, UnitElectricCharge.kiloampereHours, UnitElectricCharge.ampereHours, UnitElectricCharge.milliampereHours, UnitElectricCharge.microampereHours],
    [UnitElectricCurrent.megaamperes, UnitElectricCurrent.kiloamperes, UnitElectricCurrent.amperes, UnitElectricCurrent.milliamperes, UnitElectricCurrent.microamperes],
    [UnitElectricPotentialDifference.megavolts, UnitElectricPotentialDifference.kilovolts, UnitElectricPotentialDifference.volts, UnitElectricPotentialDifference.millivolts, UnitElectricPotentialDifference.microvolts],
    [UnitElectricResistance.megaohms, UnitElectricResistance.kiloohms, UnitElectricResistance.ohms, UnitElectricResistance.milliohms, UnitElectricResistance.microohms],
    [UnitEnergy.kilojoules, UnitEnergy.joules, UnitEnergy.kilojoules, UnitEnergy.calories, UnitEnergy.kilowattHours],
    [UnitFrequency.terahertz, UnitFrequency.gigahertz, UnitFrequency.megahertz, UnitFrequency.kilohertz, UnitFrequency.hertz, UnitFrequency.millihertz, UnitFrequency.microhertz, UnitFrequency.nanohertz],
    [UnitFuelEfficiency.litersPer100Kilometers, UnitFuelEfficiency.milesPerGallon, UnitFuelEfficiency.milesPerImperialGallon],
    [UnitIlluminance.lux],
    [UnitInformationStorage.kilobits, UnitInformationStorage.megabits, UnitInformationStorage.gigabits, UnitInformationStorage.terabits, UnitInformationStorage.petabits, UnitInformationStorage.exabits, UnitInformationStorage.zettabits, UnitInformationStorage.yottabits, UnitInformationStorage.kibibits, UnitInformationStorage.mebibits, UnitInformationStorage.gibibits, UnitInformationStorage.tebibits, UnitInformationStorage.pebibits, UnitInformationStorage.exbibits, UnitInformationStorage.zebibits, UnitInformationStorage.yobibits ],
    [UnitLength.meters, UnitLength.miles, UnitLength.feet, UnitLength.yards, UnitLength.kilometers],
    [UnitMass.grams, UnitMass.kilograms, UnitMass.ounces, UnitMass.pounds, UnitMass.stones],
    [UnitPower.terawatts, UnitPower.gigawatts, UnitPower.megawatts, UnitPower.kilowatts, UnitPower.watts, UnitPower.milliwatts, UnitPower.microwatts, UnitPower.nanowatts, UnitPower.picowatts, UnitPower.femtowatts, UnitPower.horsepower],
    [UnitPressure.newtonsPerMetersSquared, UnitPressure.gigapascals, UnitPressure.megapascals, UnitPressure.kilopascals, UnitPressure.hectopascals, UnitPressure.inchesOfMercury, UnitPressure.bars, UnitPressure.millibars, UnitPressure.millimetersOfMercury, UnitPressure.poundsForcePerSquareInch],
    [UnitSpeed.metersPerSecond, UnitSpeed.kilometersPerHour, UnitSpeed.milesPerHour, UnitSpeed.knots],
    [UnitTemperature.celsius, UnitTemperature.fahrenheit, UnitTemperature.kelvin],
    [UnitVolume.megaliters, UnitVolume.kiloliters, UnitVolume.liters, UnitVolume.deciliters, UnitVolume.centiliters, UnitVolume.milliliters, UnitVolume.cubicKilometers, UnitVolume.cubicMeters, UnitVolume.cubicDecimeters, UnitVolume.cubicMillimeters, UnitVolume.cubicInches, UnitVolume.cubicFeet, UnitVolume.cubicYards, UnitVolume.cubicMiles, UnitVolume.acreFeet, UnitVolume.bushels, UnitVolume.teaspoons, UnitVolume.tablespoons, UnitVolume.fluidOunces, UnitVolume.cups, UnitVolume.pints, UnitVolume.quarts, UnitVolume.gallons, UnitVolume.imperialTeaspoons, UnitVolume.imperialTablespoons, UnitVolume.imperialFluidOunces, UnitVolume.imperialPints, UnitVolume.imperialQuarts, UnitVolume.imperialGallons,UnitVolume.metricCups]
]

var result: String {
    let inputMeasurement = Measurement(value: input, unit: inputUnit)
    let outputMeasurement = inputMeasurement.converted(to: outputUnit)
    return formatter.string(from: outputMeasurement)

}

var body: some View {
    NavigationView {
        Form {
            Section{
                TextField("Amount", value: $input, format: .number)
                    .keyboardType(.decimalPad)
                    .focused($keyboardIsFocused)
            } header: {
                Text("Amount to convert")
            }
            Picker("Conversion", selection: $selectedUnits){
                ForEach(0..<conversions.count) {
                    Text(conversions[$0])
                }
            }
            Picker("Convert From", selection: $inputUnit) {
                ForEach(unitTypes[selectedUnits], id: \.self) {
                    Text(formatter.string(from: $0).capitalized)
                }
            }
            Picker("Convert To", selection: $outputUnit) {
                ForEach(unitTypes[selectedUnits], id: \.self) {
                    Text(formatter.string(from: $0).capitalized)
                }
            }
            Section {
                Text(result)
                    .foregroundColor(.red)
            } header: {
                Text("Results")
            }
            Section {
                TextField("About", text: ($info.detail))
            } header: {
                Text("About unit of")
            }

            }
            .navigationTitle("Converter")
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        keyboardIsFocused = false
                    }
                }
            }
            .onChange(of: selectedUnits) { newSelection in
                let units = unitTypes[newSelection]
                inputUnit = units[0]
                outputUnit = units[1]
            }
        }

    }

}

struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

1      

Your keyboardIsFocused isn't set.

1      

Need an initial value here:

@State public var info: UnitInfo

1      

@roosterby,

Thank you for your reply, I am a bit confused as to the initial value for

@State public var info: UnitInfo

As this is pointing to a struct called UnitInfo and a array called info that is outside on the ContentView.swift file in two separete files, and confused as to how it affects the init for MeasurementFormatter

import Foundation

struct UnitInfo { var name: String var detail: String

init(name: String, detail: String) {
    self.name = name
    self.detail = detail
}

}

let info = [ UnitInfo(name: "Unit of measure for acceleration", detail: "Acceleration is the rate of change of velocity. Acceleration can be expressed by SI derived units in terms of meters per second squared (m/s2)."), UnitInfo(name: "Unit of measure for planar angle and rotation", detail: "Angle is a quantity of rotation. The SI unit for angle is the radian (rad), which is dimensionless and defined to be the angle subtended by an arc that is equal in length to the radius of a circle. Angle is also commonly expressed in terms of degrees (°) and revolutions (rev)."), UnitInfo(name: "Unit of measure for area", detail: "Area is a quantity of extent in two dimensions. Area can be expressed by SI derived units in terms of square meters (m2). Area is also commonly measured in square feet (ft2) and acres (ac)."),

The snip above is not the entire info

1      

@State public var info: UnitInfo

This line just declares a variable called info and indicates that its type is UnitInfo but doesn't give it a value.

This is a separate variable from any info you may have declared in another file. Plus, your info from that other file is of type [UnitInfo], not UnitInfo.

A separate thing is that there is no benefit to declare @State variables as public, you can't really do anything all that usedul with them from outside their enclosing View anyway.

1      

@hatisushira says the same about your keyboardIsFocused variable. You tell your struct that one of its variables is going to be a boolean called keyboardIsFocused.

But you never tell the struct if keyboardIsFocused is true or false. You must initialize ALL your struct's variables when you create a new struct.

You do this by either:

  1. Pass in a value when you create a struct
  2. Declare the value with a default value.
// Paste this into Playgrounds
struct Singer {
    let nameLast = "Swift" // default declaration
    var nameFirst : String // undefined, but declared
    var isGrammyWinner = true // default declaration
}

let grammyWinner = Singer( nameFirst: "Taylor")  // initialize a struct providing a value.

let notAgrammyWinner = Singer(nameFirst: "Pauli", isGrammyWinner: false) // override default value

let anotherSinger = Singer() // this produces an ERROR. You try to create a singer without initializing all its variables.

notAgrammyWinner.isGrammyWinner

The key here is you MUST provide values for each of the structure's variables when you create a struct.

And remember this important lesson. In SwiftUI, your display elements are structs that conform to the View protocol. These structs may be created, destroyed, and recreated thousands of times a second. Each time, your struct is initialized, its variables must be populated.

It may seem like overkill for SwiftUI to destroy and recreate view structs. But this process is trivial compared to the tens of thousands of calculations the iPhone does reading GPS data, barometer data, gyroscope data, step calculations, finger swipes, data encryption, voice recognition, network background tasks, scanning faces, and serving up cat memes.

1      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Spend less time managing in-app purchase infrastructure so you can focus on building your app. RevenueCat gives everything you need to easily implement, manage, and analyze in-app purchases and subscriptions without managing servers or writing backend code.

Get Started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.