1

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
    }
}
Konrad Wright
  • 1,254
  • 11
  • 24

1 Answers1

1

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)
     }
 }
Kamran
  • 14,987
  • 4
  • 33
  • 51
  • I got the warning silenced by using guard let placemark = placemarks.value?first else { return } do you think that'll be fine? – Konrad Wright Nov 04 '18 at 10:41
  • 1
    @KonradWright Actually i am not sure how many elements are there in that `array` and i don't know the condition that returns more than one elements in the array. Still i can suggest you a better solution by seeing the code in this block. I believe you are only interested in `CA` and `US` so i will update the answer to handle those cases. – Kamran Nov 04 '18 at 10:46
  • 1
    @KonradWright I updated the answer with a better fix. – Kamran Nov 04 '18 at 11:05