Search code examples
iosxmlswift3swxmlhash

Use of undeclared type in Swift 3


I have the following class to return a list of NOAA weather observation stations. I am using it to learn how to deal with XML. However, I am getting a "Use of undeclared type 'wxObservationStations'" as an error at func returnWxStation() -> (wxObservationStations). I am using SWXMLHash to deserialize the XML, but I don't think that is my problem (though I am just learning, so it may be).

class WxObservationStations {

let wxObserStationsURL = URL(string: "http://w1.weather.gov/xml/current_obs/index.xml")

struct wxStation: XMLIndexerDeserializable {
    let stationName: String
    let stationState: String
    let latitude: Double
    let longitude: Double

    static func deserialize(_ node: XMLIndexer) throws -> wxStation {
        return try wxStation(
            stationName: node["station_name"].value(),
            stationState: node["state"].value(),
            latitude: node["latitude"].value(),
            longitude: node["longitude"].value()
        )
    }
}

public var wxObservationStations: [wxStation] = []


private func getStationNamesAndLocations(url: URL, completion:@escaping (XMLIndexer) -> ()) {

    Alamofire.request(url).responseJSON { response in
        //                print(response) // To check XML data in debug window.
        let wxStationList = SWXMLHash.parse(response.data!)
        print(wxStationList)
        completion(wxStationList)

    }
}

//The error is here:
func returnWxStation() -> (wxObservationStations) {
    getStationNamesAndLocations(url: wxObserStationsURL!, completion: { serverResponse in
        do {
            self.wxObservationStations = try serverResponse["wx_station_index"]["station"].value()

        } catch {

        }
    })
      return self.wxObservationStations
}
}

Any thoughts? The variable is declared in the class, and I would like to use it to send the data back to the requesting object. Thanks in advance.


Solution

  • The wxObservationStations is not a type, so it doesn't make sense to say

    func returnWxStation() -> (wxObservationStations) { ... }
    

    You're returning self.wxObservationStations, which is of type [wxStation]. So the method declaration should be

    func returnWxStation() -> [wxStation] { ... }
    

    By the way, your life will be much easier if you stick with Cocoa naming conventions, namely types should start with upper case letters. So rather than the wxStation type, I'd suggest WxStation.


    Your following method will not achieve what you want:

    func returnWxStation() -> [wxStation] {
        getStationNamesAndLocations(url: wxObserStationsURL!, completion: { serverResponse in
            do {
                self.wxObservationStations = try serverResponse["wx_station_index"]["station"].value()
            } catch {
    
            }
        })
    
        return self.wxObservationStations
    }
    

    The method getStationNamesAndLocations runs asynchronously and your self.wxObservationStations will not be populated by the time that returnWxStation actually returns.

    The entire purpose of the getStationNamesAndLocations method is to provide you a nice asynchronous method with completion handler. I would excise returnWxStation from your code entirely. Or do something like:

    func returnWxStation(completionHandler: ([wxStation]?) -> Void) {
        getStationNamesAndLocations(url: wxObserStationsURL!) { serverResponse in
            do {
                let stations = try serverResponse["wx_station_index"]["station"].value()
                completionHandler(stations)
            } catch {
                completionHandler(nil)
            }
        }
    }
    

    And you'd use it like so:

    returnWxStation() { stations in
        guard let stations = stations else {
            // handle error here
            return
        }
    
        // use `stations` here
    }
    
    // but not here