Home > Enterprise >  passing a struct type as a parameter throwing initialization error
passing a struct type as a parameter throwing initialization error

Time:12-14

I have the following code which has 3 objects which are then part of a 4th object. I'm getting errors trying to create the init method for the aggregate object (GTFS) because I'm passing (or trying to pass) the type of the 3 component objects (Stop, Route, Trip). I'm not sure why those have to be initialized before just their types being used.


protocol GTFSObject {
    static var fileName: String { get }
    init(csvRow: [String: String])
}

struct Stop: GTFSObject {
    static let fileName = "stops.txt"
    
    let stopID: String
    let stopCode: String
    let stopName: String
    let stopDesc: String
    let stopLat: Double
    let stopLon: Double
    let locationType: Int
    let parentStation: String
    
    init(csvRow: [String: String]) {
        self.stopID = csvRow["stop_id"]!
        self.stopCode = csvRow["stop_code"]!
        self.stopName = csvRow["stop_name"]!
        self.stopDesc = csvRow["stop_desc"]!
        self.stopLat = Double(csvRow["stop_lat"]!)!
        self.stopLon = Double(csvRow["stop_lon"]!)!
        self.locationType = Int(csvRow["location_type"]!)!
        self.parentStation = csvRow["parent_station"]!
    }
}

struct Trip: GTFSObject {
    static let fileName = "trips.txt"
    
    let routeID: String
    let serviceID: String
    let tripID: String
    
    init(csvRow: [String: String]) {
        tripID = csvRow["trip_id"] ?? ""
        routeID = csvRow["route_id"] ?? ""
        serviceID = csvRow["service_id"] ?? ""
    }
}

struct Route: GTFSObject {
    static let fileName = "trips.txt"
    
    let routeID: String
    let agencyID: String
    let routeShortName: String
    let routeLongName: String
    let routeDesc: String
    let routeType: Int
    let routeURL: String
    let routeColor: String
    let routeTextColor: String
        
    init(csvRow: [String: String]) {
      routeID = csvRow["route_id"] ?? ""
      agencyID = csvRow["agency_id"] ?? ""
      routeShortName = csvRow["route_short_name"] ?? ""
      routeLongName = csvRow["route_long_name"] ?? ""
      routeDesc = csvRow["route_desc"] ?? ""
      routeType = Int(csvRow["route_type"] ?? "0") ?? 0
      routeURL = csvRow["route_url"] ?? ""
      routeColor = csvRow["route_color"] ?? ""
      routeTextColor = csvRow["route_text_color"] ?? ""
    }
}

class GTFS {
    let routes: [Route]
    let stops: [Stop]
    let trips: [Trip]
    
    init(gtfsFolderUrl: URL) {
        self.stops = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Stop.self)
        self.trips = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Trip.self)
        self.routes = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Route.self)
    }
    
    private func init_struct_from_url<GTFSType>(gtfsFolderUrl: URL, type: GTFSType.Type) -> [GTFSType] where GTFSType : GTFSObject{
        var returnList: [GTFSType] = []
        let rows = try! NamedCSV(url: GTFS_FOLDER_URL.appendingPathComponent(type.fileName), delimiter: CSVDelimiter.comma, loadColumns: false).rows
        for row in rows {
            returnList.append(type.init(csvRow: row))
        }
        return returnList
    }
}

The error I get is

'self' used in method call 'init_struct_from_url' before all stored properties are initialized

I don't know why I have to initialize the properties of the struct just to pass the type of the struct to this other function. What am I missing?

CodePudding user response:

It's not about the three types that you are passing to init_struct_from_url. It's about the call init_struct_from_url itself.

You are actually calling:

self.init_struct_from_url(...)
^^^^^

The error is saying that that use of self is not allowed, because self is not initialised. If init_struct_from_url uses a property in self, it could see an uninitialised value.

Since init_struct_from_url doesn't actually use self at all and is just a helper function, you can make it an inner function of init:

init(gtfsFolderUrl: URL) {

    func structFromUrl<GTFSType>(gtfsFolderUrl: URL, type: GTFSType.Type) -> [GTFSType] where GTFSType : GTFSObject{
        var returnList: [GTFSType] = []
        let rows = try! NamedCSV(url: GTFS_FOLDER_URL.appendingPathComponent(type.fileName), delimiter: CSVDelimiter.comma, loadColumns: false).rows
        for row in rows {
            returnList.append(type.init(csvRow: row))
        }
        return returnList
    }

    self.stops = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Stop.self)
    self.trips = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Trip.self)
    self.routes = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Route.self)
}
  • Related