Search code examples
iosswiftswift4cllocationpromisekit

Unable to unwrap Promise<[CLPlacemark]>


I have a method that attempts to update my authorized status.

Using PromiseKit 6, Swift 4.2, I can't seem to get my Promise<[CLPlacemark]> to just be a CLPlacemark.

This causes a chain of errors of

Value of type 'Promise<[CLPlacemark]>' has no member 'foo'

Here's a look at my code:

func updateAuthStatus(status: CLAuthorizationStatus) {
    if status == .authorizedWhenInUse {
        titleLabel.isHidden = true
        bigIconView.isHidden = true
        descriptionLabel.isHidden = true
        grantBtn.isHidden = true
        titleLabel1.isHidden = false
        loaderView.isHidden = false
        loaderView.resumeSpinning()
        CLLocationManager.requestLocation().compactMapValues { location in
            return self.coder.reverseGeocode(location: location)
        }.compactMapValues { placemark -> Void in
            if placemark.ISOcountryCode == "CA" {
                self.seal.fulfill(())
            } else if placemark.ISOcountryCode == "US" {
                if self.allowedStates.contains(placemark.administrativeArea ?? "") {
                    self.seal.fulfill(())
                } else {
                        self.seal.reject(LocationError.InvalidState(placemark.administrativeArea ?? ""))
                }
            } else {
        self.seal.reject(LocationError.InvalidCountry(placemark.ISOcountryCode ?? ""))
            }
        }
    }
    else if status == .denied || status == .restricted {
        if denied == false {
            self.seal.reject(LocationError.Unknown)
        }
        denied = true
    }
}

Solution

  • As you mentioned, this promise is returning an array of CLPlacemark objects so you need to get the specific placemark from the array and then use it. Here is the sample by accessing the first placemark in the array.

    .compactMapValues { placemarks -> Void in
                guard let placemark = placemarks.first else { return }
    
                if placemark.ISOcountryCode == "CA" {
                    self.seal.fulfill(())
                } else if placemark.ISOcountryCode == "US" {
                    if self.allowedStates.contains(placemark.administrativeArea ?? "") {
                        self.seal.fulfill(())
                    } else {
                      self.seal.reject(LocationError.InvalidState(placemark.administrativeArea ?? ""))
                    }
                } else {
            self.seal.reject(LocationError.InvalidCountry(placemark.ISOcountryCode ?? ""))
                }
            }
    

    Edit

    To handle US and CA, related placemark for that country can be extracted as below,

    .compactMapValues { placemarks -> Void in
           if let ca = placemarks.filter{ $0.ISOcountryCode == "CA"}.first {
                self.seal.fulfill(())
           } else if let usa = placemarks.filter{ $0.ISOcountryCode == "US"}.first {
                if self.allowedStates.contains(usa.administrativeArea ?? "") {
                    self.seal.fulfill(())
                } else {
                    let error = LocationError.InvalidState(usa.administrativeArea ?? "")
                    self.seal.reject(error)
                }
        } else {
             let error = LocationError.InvalidCountry(placemarks.first?.ISOcountryCode ?? "")
             self.seal.reject(error)
         }
     }