AlamofireObjectMapper Generic parameter 'T' could not be inferred - ios

i'm trying to have a system where all my api requests path through one function and map them to the corresponding object
func sendApi<T>(url : String , httpMethod : HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil , callbackSuccess : #escaping (T) -> () , callbackFailure : #escaping (T) -> ()) where T : Mappable {
Alamofire.request(url, method: httpMethod, parameters: parameters , encoding: encoding, headers: headers).responseObject{(response: (DataResponse<T>))in
switch response.result {
case .success :
let result = Mapper<T>().map(JSONObject: response.value)!
callbackSuccess(result)
break;
case .failure(let error):
if((error as NSError).code == ErrorResponse.noInternetConnection){
// errorCallBack(ErrorResponse.noInternetConnectionString)
}
// errorCallBack(error.localizedDescription)
print(error.localizedDescription)
break;
}
}
}
but when i try to call the function inside a get method for example
func testApiGet(url: String , packageId : Int ,callback :#escaping (myObject) -> Void , errorCallBack : #escaping (String) -> Void ){
let token = spm.getUserToken()
let headers = ["X-Auth-Token" : token]
let newUrl = url + "?packageId=" + String(packageId)
sendApi(url: url, httpMethod: HTTPMethod.get , parameters: nil, encoding: JSONEncoding.default, headers: headers, callbackSuccess: {(jsonObject) in
} , callbackFailure:{ (jsonObject)in
})
}
i get the error "Generic parameter 'T' could not be inferred"
of course i can set the type of the object
(response: (DataResponse<myObject>)
and the error will go.
my question is how solve this error to make it fully generic

It does not make sense that your error handler and your success handler have the same type T: Mappable. You are only going to get a mapped object in the success handler. The error handler should be something like (Error) -> ().
Secondly your function is generic with respect to the parameter type of the closure arguments, but when you are calling the function you are not specifying the type:
sendApi(url: url, httpMethod: HTTPMethod.get , parameters: nil, encoding: JSONEncoding.default, headers: headers, callbackSuccess: {(jsonObject) in
} , callbackFailure:{ (jsonObject)in
})
The compiler therefore has no idea what type you are expecting and thats why its complaining that it cannot infer the type here. You need to explicitly provide the parameter type because that is what determines what version of the generic gets invoked:
sendApi(url: url, httpMethod: HTTPMethod.get , parameters: nil, encoding: JSONEncoding.default, headers: headers, callbackSuccess: {(jsonObject: MyMappableType) in
} , callbackFailure:{ (error: Error)in
})

Related

How to move return type to next line in AppCode in function declaration?

How to setup code style in AppCode in order to move return type to next line if the declaration is too long?
Here is an example:
public func requestString(_ method: Alamofire.HTTPMethod,
_ url: URLConvertible,
parameters: [String: Any]? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil)
-> Observable<(HTTPURLResponse, String)> {
return SessionManager.default.rx.responseString(
method,
url,
parameters: parameters,
encoding: encoding,
headers: headers
)
}
The following settings should do exactly what you need

extra argument in call alamofire swift 3

I am trying to make an alamofire post request, I am sending a parameter and a body , as following:
static func sendFeedbackResultOldCustomer(customerId: String?,fbackAnswers:String? ,answers: String?, completion: #escaping (Bool , String?) ->() ){
let parameters: Parameters = ["customer_id":customerId!,"customer_new":"0","x-session":getXSession()]
request(urlString: APIStrings.feedbackSent, parameters: parameters, method: .post, headers: nil, encoding: answers, updateXsession: false) { (success, error, errorMsg, response) in
if(success) {
completion(true, nil)
}
else {
completion(false, response?.result.error as? String)
}
}
}
the request code:
fileprivate static func request (urlString: String!, parameters: Parameters?, method: HTTPMethod, headers: HTTPHeaders?,encoding: String!, updateXsession: Bool, completion: #escaping(Bool, Error?, String?, DataResponse<Any>?) ->()) {
Alamofire.request(urlString, method: method, parameters: parameters, headers: headers,encoding:encoding).responseJSON { (response) in// here is the error (extra argument method in call)
let contentType = response.response?.allHeaderFields["X-Session"] as? String
if (updateXsession)
{
UserDefaults.standard.set(contentType, forKey: "x-session")
}
let success = checkIfSuccess(response: response)
if(success){
completion(success, nil, nil, response)
} else {
completion(success, response.error, "Failed", nil)
}
}
in the alamofire request, im getting the following error : Extra argument in call. any idea whats going on?
parametes im sending:
let parameters: Parameters = ["customer_id":customerId!,"customer_new":"0","x-session":getXSession()]
body im trying to send:
X_types = [{"type_id":"17","value":"3"},{"type_id":"12","value":"test"},{"type_id":"14","value":"4"},{"type_id":"19","value":"3"},{"type_id":"16","value":"4"},{"type_id":"13","value":"3"},{"type_id":"18","value":"4"},{"type_id":"15","value":"4"},{"type_id":"2","value":"4"},{"type_id":"11","value":"1"},{"type_id":"1","value":"3"},{"type_id":"8","value":"3"},{"type_id":"6","value":"2"},{"type_id":"4","value":"22-09-2017 - 12:1"},{"type_id":"5","value":"Test"}]
X_types is been sent in the encoding , as a string (x_types is as string type)
The signature for alamofire request is: public func request(_ url: URLConvertible, method: Alamofire.HTTPMethod = default, parameters: Parameters? = default, encoding: ParameterEncoding = default, headers: HTTPHeaders? = default). I think you have mismatched the signature.
Try
let request = Alamofire.request(url, method: HTTPMethod.post, parameters: params, encoding: JSONEncoding.default, headers: header)
request.responseJSON { response in
}

Error with Generics with clousers i.e. '(Any) -> Void' is not convertible to '(T) -> Void

I am using Generics with #escaping closure but getting error on completion(JSON) as -
'(Any) -> Void' is not convertible to '(T) -> Void'
Below is my tried code
static func getData<T>(inputUrl:String,parameters:[String:Any],completion:#escaping(_: T)->Void){
let url = URL(string: inputUrl)
Alamofire.request(url!, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON { response in
let nilValue = ""
if let JSON = response.result.value {
completion(JSON)
}
else {
completion(nilValue)
}
}
}
The problem is that you are not using the generic type, T anywhere in your code and you just return a value of type Any regardless of the type of T.
If you really want your function to be generic, you should cast response.result.value to T and return that value in the completion handler. Moreover, don't return an empty String in case of failure, make the closure accept an optional and return nil in case of failure.
static func getData<T>(inputUrl:String,parameters:[String:Any],completion:#escaping(_: T?)->Void){
let url = URL(string: inputUrl)
Alamofire.request(url!, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON { response in
if let json = response.result.value as? T {
completion(json)
}
else {
completion(nil)
}
}
}

How to create a block response like Alamofire Responses?

May this question be dumb, but I was looking a way to create optional responses like Alamofire 4.0 have (eg. responseJSON,responseData, responseString etc). For example, in my project I have BaseService which make the request (using alamofire) then handle the response (for erros, if has, it calls a exception class which shows a message an break the flow). So, I have subclasses that inherit from my BaseService, and my methods has completions blocks who parse and pass any data (or error if need) from BaseService.
Theen, my question is: my BaseService request function may return (as block) a response, json or an error, ex: completionHandler(response,json, error) or completionHandler(nil, json, nil)
So when I don't need a response or json, just want verify if error isn't nil I've to do like this:
myFunc() { ( _ , _,error) in }
How do I do to get only the block that I want? Like Alamofire do with his response?
You can divide your completionHandler at you BaseService class to each service function to onSuccess and onFail ... etc
Example:
func logInUser( _ userEmail : String, userPassword : String, onSuccess: #escaping (Any?)-> Void, onFail : #escaping (Error?) ->(Void)) {
let url : URLConvertible = urls.loginUser
let parameters = ["email" : userEmail, "password" : userPassword]
let header = ["Authorization" : APPSECRETKEY ]
alamofireManager.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: header).responseJSON(completionHandler: { response in
if response.result.value != nil && response.result.error == nil {
onSuccess(response.result.value)
}
else
{
onFail(response.result.error)
}
})
}
When you call your service function:
BaseService.sharedInstance.logInUser("email", userPassword: "password",
onSuccess: { responseValue in
},
onFail: { error in
})

Expression type 'DataRequest' is ambiguous without more context Swift

I use Alamofire for my request in this function and I have this error if someone could help me please thank in advance.
Expression type 'DataRequest' is ambiguous without more context
func report(_ track: Track, completionHandler: #escaping (_ error: NSError?) -> Void) {
var headers:[String:String] = [:]
if AuthManager.defaultAuthManager().isLoggedIn() {
headers = ["Authorization": "Bearer " + AuthManager.defaultAuthManager().authToken.token!]
}
let params: [String: Any] = ["trackCode": track.code]
let urlString = Cizoo.APIBaseUrl + CizooScheme.report
CizooAPI.manager.request(urlString, method: .post, parameters: params, encoding: .JSONEncoding.default, headers: headers as HTTPHeaders)
.validate()
.responseJSON(completionHandler: { // Error at this line
response in
switch response.result {
case .success:
completionHandler(error: nil)
case .failure(let error):
completionHandler(error: error)
}
})
}
From the Alamofire source code you can see that the declaration of the method is:
#discardableResult
open func request(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil)
-> DataRequest
{
var originalRequest: URLRequest?
do {
originalRequest = try URLRequest(url: url, method: method, headers: headers)
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
Which in your case probably the urlString is not conforming to the URLConvertible protocol.
Thanks !
Finally, It was a concern of type declaration
Here is the code solved :
func report(_ track: Track, completionHandler: #escaping (_ error: NSError?) -> Void) {
var headers:HTTPHeaders? = [:]
let params:Parameters? = ["trackCode": track.code]
let encoding:ParameterEncoding = JSONEncoding.default
let method:HTTPMethod = .post
let urlString:URLConvertible = (Cizoo.APIBaseUrl + CizooScheme.report)
if AuthManager.defaultAuthManager().isLoggedIn() {
headers = ["Authorization": "Bearer " + AuthManager.defaultAuthManager().authToken.token!]
}
CizooAPI.manager.request(urlString, method: method, parameters: params, encoding: encoding, headers: headers)
.validate()
.responseJSON(completionHandler: {
response in
switch response.result {
case .success:
completionHandler(nil)
case .failure(let error):
completionHandler(error as NSError?)
}
})
}

Resources