Search code examples
iosswiftswiftuiinitializationinitializer

Problems with class initialization


I think it's a simple problem but a head scratcher. I'm getting a ....has no initializers error when there actually are initializers.

Here is my code:

(Edit: I've updated the PatientData class to include all the additional variables. I didn't think they made a difference in figuring out the problem, so for the sake of brevity I left them out.)

Data Structures

class PatientData: Identifiable, ObservableObject
{
    let id = UUID()
    
    @Published var patientName: String = "Name"
    @Published var patientAge: String = "Age"
    @Published var patientDOB: String = "DOB"
    @Published var patientPhone: String = "Phone"
    @Published var patientAddress: PatientAddress

    struct PatientAddress
    {
        var patientStreetAddress: String = "Street"
        var patientCity: String = "City"
        var patientState: String = "State"
        var patientZip: String = "Zip"
        
        init(patientStreetAddress: String, patientCity: String, patientState: String, patientZip: String)
        {
            self.patientStreetAddress = patientStreetAddress
            self.patientCity = patientCity
            self.patientState = patientState
            self.patientZip = patientZip
        }
    }
    
    @Published var facilityName: String = "Facility"
    @Published var facilityRoom: String = "Room Number"
    @Published var facilityFloor: String = "Floor"
    @Published var facilityPhoneNumber: String = "Phone Number"
    
    init(patientName: String, patientAge: String, patientDOB: String, patientPhone: String, patientAddress: PatientAddress, facilityName: String, facilityRoom: String, facilityFloor: String, facilityPhoneNumber: String)
    {
        self.patientName = patientName
        self.patientAge = patientAge
        self.patientDOB = patientDOB
        self.patientPhone = patientPhone
        self.patientAddress = patientAddress
        self.facilityName = facilityName
        self.facilityRoom = facilityRoom
        self.facilityFloor = facilityFloor
        self.facilityPhoneNumber = facilityPhoneNumber
    }
    init() {}
}

Content View

struct ContentView: View
{
    @ObservedObject var patient = PatientData()
    ...
}

Solution

  • Note that:

    PatientData()
    

    is an equivalent of:

    PatientData.init()
    

    Which means that if you want to create your PatientData this way:

    @ObservedObject var patient = PatientData()
    

    you need to provide a matching init method (it can be empty as all your @Published properties have already a default value):

    init() { }
    

    EDIT

    Looking at your full code, it seems like one of your properties has no initial value:

    @Published var patientAddress: PatientAddress
    

    An empty init will work only when all your properties are already initialised, which means you need to assign some value to your patientAddress:

    @Published var patientAddress = PatientAddress()
    

    However, for this to work, you'd need to add an empty init in PatientAddress as well:

    struct PatientAddress {
        ...
        init() {}
    }
    

    NOTE

    All your code could be much simpler without all these initialisers. If you only use empty init methods you don't have to declare them (they are auto-generated for structs if there are no other initialisers):

    class PatientData: Identifiable, ObservableObject {
        let id = UUID()
    
        @Published var patientName: String = "Name"
        @Published var patientAge: String = "Age"
        @Published var patientDOB: String = "DOB"
        @Published var patientPhone: String = "Phone"
        @Published var patientAddress: PatientAddress = PatientAddress()
    
        @Published var facilityName: String = "Facility"
        @Published var facilityRoom: String = "Room Number"
        @Published var facilityFloor: String = "Floor"
        @Published var facilityPhoneNumber: String = "Phone Number"
    }
    
    extension PatientData {
        struct PatientAddress {
            var patientStreetAddress: String = "Street"
            var patientCity: String = "City"
            var patientState: String = "State"
            var patientZip: String = "Zip"
        }
    }
    

    Also, Swift can infer types automatically. You don't usually have to declare types explicitly:

    @Published var patientPhone = "Phone"
    @Published var patientAddress = PatientAddress()