Feldur
Feldur

Reputation: 1169

Closure downcast causes EXC_BAD_INSTRUCTION fault

In a class I'm writing to work with WeatherUnderground, I need a number of functions all nearly identical to this function, which in this form works fineonC:

func currentConditions(completion: (result: WUConditionResponse?) -> Void) -> Request {
    url = urlBuilder("conditions")
    let request = Alamofire.request(.GET, url)
        .validate()
        .responseObject { (response: Result<WUConditionResponse, NSError>) in
            completion(result: response.value)
    }
    return request
}

Rather than write them all separately, I tried this:

private typealias AFCompletion = (result: EVObject?) -> Void
private func current(command: String, onCompletion: AFCompletion) -> Request {
    let function = {(completion: AFCompletion) -> Request in
        self.url = self.urlBuilder(command)
        let request = Alamofire.request(.GET, self.url)
            .validate()
            .responseObject { (response: Result<EVObject, NSError>) in
                completion(result: response.value!)
        }
        return request
    }
    return function(onCompletion)
}

Followed by

func currentConditions(completion: (result: WUConditionResponse?) -> Void) -> Request {
    let myCompletion = completion as! AFCompletion
    return current("conditions", onCompletion: myCompletion)
}

where WUConditionResponse is a subclass of EVObject. I then use the construct with the statement, unchanged from what was working:

    foo.currentConditions { (conditions: WUConditionResponse?) in
        print(conditions)
    }

Done this way, I get an EXC_BAD_INSTRUCTION fault on the downcast to AFCompletion. I'm at a loss to see the problem. Why does the downcast fault? Complete answers notwithstanding, how might I debug this further?

Upvotes: 1

Views: 67

Answers (1)

luk2302
luk2302

Reputation: 57184

That is not possible the way you are trying to do it. The closure you pass in

foo.currentConditions { (conditions: WUConditionResponse?) in
    print(conditions)
}

accepts only WUConditionResponse, one specific subclass of EVObject. If you cast that closure to AFCompletion, the resulting closure has to accept every EVObject which it does not.

What you can do is create a second only calling the completion if the actually passed in object is of correct type rather than casting:

func currentConditions(completion: (result: WUConditionResponse?) -> Void) -> Request {
    let myCompletion : AFCompletion = { res in 
        if res != nil || res! is WUConditionResponse {
             return completion(res as! WUConditionResponse?)
        }
        return false // default return
    }
    return current("conditions", onCompletion: myCompletion)
}

Upvotes: 1

Related Questions