Tung Cheng Tung Cheng - 3 months ago 73
Swift Question

test CLGeocoder geocodeAddressString method placemarks is always nil

Codes are from book , It's always failed in the first XCTFail(), I tried it on both device and simulator, It should't be network issue, look into the error, it shows

Optional(Error Domain=kCLErrorDomain Code=2 "(null)")


func test_GeocoderWorksAsExpected() {
let expectation = expectationWithDescription("Wait for geocode")
CLGeocoder().geocodeAddressString("Infinite Loop 1, Cupertino") {
(placemarks, error) -> Void in
let placemark = placemarks?.first

let coordinate = placemark?.location?.coordinate
guard let latitude = coordinate?.latitude else {
XCTFail(); return
}
guard let longitude = coordinate?.longitude else {
XCTFail(); return
}
XCTAssertEqualWithAccuracy(latitude, 37.3316851, accuracy: 0.000001)
XCTAssertEqualWithAccuracy(longitude, -122.0300674, accuracy: 0.000001)

expectation.fulfill()
}
waitForExpectationsWithTimeout(3, handler: nil)
}

Rob Rob
Answer

You say it shouldn't be a network error, but that's precisely what a CLErrorDomain error with a code of 2 is (CLError.Network). You can get that for a variety of reasons. For example, I got it when I tried monitoring the communication with Charles, but hadn't yet told my computer to trust the Charles certificate. But once I did, that error went away. You might want to confirm that you're not using a proxy server or other networking that interferes with TLS/HTTPS requests.

As an aside, I'd also suggest:

  • You should defer the fulfillment of the expectation (so it gets fulfilled regardless of what path you take out of that closure); and
  • You might want to reduce the accuracy of that latitude and longitude error check (as I found my results differed ever so slightly).

So, perhaps something like:

func testGeocoder() {
    let expectation = expectationWithDescription("Wait for geocode")
    CLGeocoder().geocodeAddressString("Infinite Loop 1, Cupertino") { placemarks, error in
        defer { expectation.fulfill() }

        guard error == nil else {
            XCTFail(error!.localizedDescription); return
        }

        guard let coordinate = placemarks?.first?.location?.coordinate else {
            XCTFail("No coordinate"); return
        }

        XCTAssertEqualWithAccuracy(coordinate.latitude, 37.3316851, accuracy: 0.001, "Latitude doesn't match")
        XCTAssertEqualWithAccuracy(coordinate.longitude, -122.0300674, accuracy: 0.001, "Longitude doesn't match")
    }
    waitForExpectationsWithTimeout(3, handler: nil)
}