Generic parameter 'T' could not be inferred while calling a method - ios

I am getting below error
Generic parameter 'T' could not be inferred
I have created a method and when I am trying to call that method then getting that error. I am adding both methods below.
func requestNew<T> ( _ request: URLRequest, completion: #escaping( Result< T , NetworkError>) -> Void ) where T : Decodable {
URLCache.shared.removeAllCachedResponses()
print("URL \((request.url as AnyObject).absoluteString ?? "nil")")
//use the currentrequest for cancel or resume alamofire request
currentAlamofireRequest = self.sessionManager.request(request).responseJSON { response in
//validate(statusCode: 200..<300)
if response.error != nil {
var networkError : NetworkError = NetworkError()
networkError.statusCode = response.response?.statusCode
if response.response?.statusCode == nil{
let error = (response.error! as NSError)
networkError.statusCode = error.code
}
//Save check to get the internet connection is on or not
if self.reachabilityManager?.isReachable == false {
networkError.statusCode = Int(CFNetworkErrors.cfurlErrorNotConnectedToInternet.rawValue)
}
completion(.failure(networkError))
}else{
print("response --- > ",String(data: response.data!, encoding: .utf8) ?? "No Data found")
if let responseObject = try? JSONDecoder().decode(T.self, from: response.data!) {
completion(.success(responseObject.self))
}else {
}
}
}
}
Below is screenshot of error
![
]1
func getVersion1(complete :#escaping (Response<Version>) -> Void, failure:#escaping onFailure) {
self.network.requestNew(self.httpRequest) { (result) in
print("hello")
}

When Swift cannot infer the generic parameter, although it accepts the generic declaration of the method, you can specify the type by passing type fixed parameters.
Try this:
func getVersion1(complete :#escaping (Response<Version>) -> Void, failure:#escaping onFailure) {
self.network.requestNew(self.httpRequest) { (result: Result<Version, NetworkError>) in
print("hello")
}
}
You may need to change Result<Version, NetworkError> to Result<SomeDecodableType, NetworkError>, if Version is not the type you expect from the request.

Related

Generic Encodable could not be inferred

I have an API class with the following function:
static func JSONPostRequest<EncodableType:Codable, DecodableType:Codable>(endpoint: String, jsonData: EncodableType, callback: #escaping (DecodableType) -> Void, clientErrorCallback: #escaping (Error) -> Void, responseErrorCallback: #escaping (URLResponse) -> Void, requestHeaders: [String: String]?) {
// Encoding the data into JSON
var jsonData: Data = Data();
do {
jsonData = try JSONEncoder().encode(jsonData)
}
catch {
print("JSON Encode")
return ;
}
// Setup the request
var request: URLRequest = URLRequest(url: URL(string: self.endpoint + self.apiVersion + "/" + endpoint)!)
request.httpMethod = "POST"
request.httpBody = jsonData
// Set the custom headers
if(requestHeaders != nil) {
for (headerKey, headerValue) in requestHeaders! {
request.setValue(headerValue, forHTTPHeaderField: headerKey)
}
}
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Was there an error in request?
if error != nil {
clientErrorCallback(error!)
return
}
// Response code is 2XX?
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
responseErrorCallback(response!)
return
}
// Has mime type fine?
guard let mime = response!.mimeType, mime == "application/json" else {
print("Wrong MIME type!")
return
}
let decoder = JSONDecoder()
let loginResponse = try! decoder.decode(DecodableType.self, from: data!)
callback(loginResponse)
}
task.resume()
}
But when I would like to call it from my login view ... :
API.JSONPostRequest(
endpoint: "login",
jsonData: LoginRequest(username: self.username, password: self.password),
callback: { loginResponse in
// success callback
if loginResponse.success && loginResponse.token != "" {
callback(loginResponse)
}
else {
// backend logic error
}
}, clientErrorCallback: { error in
// client error
}, responseErrorCallback: { urlResponse in
// response error
}, requestHeaders: headers
)
... I get the following error message:
Generic parameter 'EncodableType' could not be inferred
Here's my LoginRequest implementation:
struct LoginRequest: Codable {
var username: String;
var password: String;
}
The error message shows near the first line of the function call, near "API.JSONPostRequest(".
What could be the problem here?
You didn't provide a type for loginResponse, and there's no way from this code to guess what it is. Looking at the code you've posted, I can't figure out what the response is supposed to be (nothing you've posted here has a .success or .token value).
I assume you meant to add the following code:
struct LoginResponse: Codable {
var success: Bool
var token: String
}
And I assume somewhere there is a variable callback of type (LoginResponse) -> Void.
With that type, you'll still need to let the compiler know it's what you expect. It has no way to guess of the infinite number of types this could return, that you want LoginResponse:
...
callback: { (loginResponse: LoginResponse) in
...
Alternately, you can adjust your type signature to pass the expected type, for example:
static func JSONPostRequest<Request, Response>(endpoint: String,
jsonData: Request,
returning: Response.Type = Response.self,
callback: #escaping (Response) -> Void,
clientErrorCallback: #escaping (Error) -> Void,
responseErrorCallback: #escaping (URLResponse) -> Void,
requestHeaders: [String: String]?)
where Request: Encodable, Response: Decodable {
This would allow you to pass returning: LoginResponse.self, which can be nicer than embedding it in the closure:
...
returning: LoginResponse.self,
callback: { loginResponse in
...
(That said, what I'm discussing here fixes the fact that DecodableType is actually ambiguous. The fact that you're getting an error on EncodableType suggests that you have other type-mismatches. I recommend simplifying this to a minimal example that actually demonstrates the problem in a playground. As you've written it, I had to guess at a bunch of extra code.)

In retrieving JSON data, whats the point of having a completion block return Void?

So we have this function that retrieves JSON data and presents it in its completion block, what I'm trying to understand is why use the signature: ((Data) -> Void) instead of just (Data), is the void really necessary? Here is the function:
typealias JSONData = ((Data) -> Void)
func getJSONData(type: String, urlExtension: String, completion: #escaping JSONData) {
let request = URLRequest(url: URL(string:"\(baseURL)\(type)/\(urlExtension)?api_key=\(apiKey)&region=US&append_to_response=videos,images,releases")! )
let dataTask = session.dataTask(with: request, completionHandler: { (data, response, error) in
if error == nil {
if let httpResponse = response as? HTTPURLResponse {
switch (httpResponse.statusCode) {
case 200:
if let data = data {
completion(data)
}
default:
print(httpResponse.statusCode)
}
}
} else {
DispatchQueue.main.async {
if let error = error {
print("Error: \(error.localizedDescription)") }
return
}
}
})
dataTask.resume()
}
Swift syntax dictates that you must declare closures with a return type after the ->.
You have two options:
typealias JSONData = (Data) -> Void
typealias JSONData = (Data) -> ()
I see Apple using #1 most frequently.

Alamofire API request is getting failed with responseSerializationFailed in swift 3

I am calling normal API call with Alamofire, And I am not passing any data with that in networking manager class.
My Networking class is
func executeGetRequest(url:String,requestVC:UIViewController,completionHandler:#escaping (_ responseObject:Any?) -> Void!,failureHandler:#escaping (_ connectionError:NSError?) -> Void!){
//Checking internet alert
if !self.isConnectedToInternet(){
// requestVC.showAlert(kText_AppName, message: kText_NoInternet)
return
}
requestVC.showLoader()
Alamofire.request(url).responseJSON {
(response:DataResponse) in
requestVC.removeLoader()
switch(response.result) {
case .success(_):
if response.result.value != nil{
completionHandler (response.result.value)
}
break
case .failure(let error):
failureHandler (error as NSError?)
break
}
}
}
and i am calling it from my main class
kNetworkManager.executeGetRequest(url: kAppAccessTokenURL, requestVC: self, completionHandler: {
(responseObject) -> () in
print("responseObject:\(responseObject!)")
}, failureHandler: {(error)-> () in
print("response object:\(error!)")
self.showAlert(message: (error?.description)!, title: kText_AppName)
if error?._code == NSURLErrorTimedOut {
//timeout here
self.showAlert(message: kText_timeout, title: kText_AppName)
}
})
Its getting always request fail and showing error as responseSerializationFailed
if I call directly in Main Class without manager class like
Alamofire.request(kAppAccessTokenURL).responseString { response in
I am able to getting response, can anyone suggest me where getting wrong in Network class.
Here you
Alamofire.request(kAppAccessTokenURL).responseString
and there
Alamofire.request(url).responseJSON
look to that
let jsonText = "{\"first_name\":\"Sergey\"}"
var dictonary:NSDictionary?
if let data = jsonText.dataUsingEncoding(NSUTF8StringEncoding) {
do {
dictonary = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject]
if let myDictionary = dictonary
{
print(" First name is: \(myDictionary["first_name"]!)")
}
} catch let error as NSError {
print(error)
}
}

Swift 2.0 migration error with alamofire

I am trying to use this piece of code I got raywenderlich.com in Xcode 7. But at the return line is giving me error saying
Cannot convert return expression of type (NilLiteralConvertible,
NilLiteralConvertible) to return type Result<UIImage>
extension Alamofire.Request {
public static func imageResponseSerializer() -> GenericResponseSerializer<UIImage> {
return GenericResponseSerializer { request, response, data in
if data == nil {
return (nil, nil)
}
let image = UIImage(data: data!, scale: UIScreen.mainScreen().scale)
return (image, nil)
}
}
public func responseImage(completionHandler: (NSURLRequest, NSHTTPURLResponse?, UIImage?, NSError?) -> Void) -> Self {
return response(responseSerializer: Request.imageResponseSerializer(), completionHandler: completionHandler)
}
}
See original code at http://www.raywenderlich.com/85080/beginning-alamofire-tutorial
It looks like when you converted your project to Swift 2 you also upgraded to AlamoFire 2.x. The tutorial was written for Swift 1.2 where the closure's signature was:
(NSURLRequest?, NSHTTPURLResponse?, NSData?) -> (SerializedObject?, NSError?)
With AlamoFire 2 the signature is now:
(NSURLRequest?, NSHTTPURLResponse?, NSData?) -> Result<SerializedObject>
This means your method needs to return .Success(image!) in the passing condition and .Failure(data, myError) in the failing condition. It also means you can't just pass image without unwrapping since that initializer is nullable and the result's parameter is not.
Your serializer could look something like this:
return GenericResponseSerializer { request, response, data in
guard let validData = data else {
let error = ...
return .Failure(data, error)
}
guard let image = UIImage(data: validData, scale: UIScreen.mainScreen().scale) else {
let error = ...
return .Failure(data, error)
}
return .Success(image)
}
For your error you could either define your own ErrorType enum that will be helpful to you or use AlamoFire.Error:
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: "Image parsing failed.")
Your responseImage function will need a similar change:
public func responseImage(completionHandler: (NSURLRequest?, NSHTTPURLResponse?, Result<UIImage>) -> Void) -> Self {
return response(responseSerializer: Request.imageResponseSerializer(), completionHandler: completionHandler)
}
This will in turn require you to update code that uses responseImage but those error messages should be helpful.
It work for me, remove old Alamofire from Ray's sample, and add last version form git https://github.com/Alamofire/Alamofire, and change sample XMLResponseSerializer , for UIImage it looks like :
extension Alamofire.Request {
public static func imageResponseSerializer() -> ResponseSerializer<UIImage, NSError> {
return ResponseSerializer { request, response, data, error in
guard error == nil else { return .Failure(error!) }
guard let validData = data else {
let failureReason = "Image parsing failed."
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
guard let image = UIImage(data: validData, scale: UIScreen.mainScreen().scale) else {
let failureReason = "Image format failed."
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: failureReason)
return .Failure( error)
}
return .Success(image)
}
}
public func responseImage(completionHandler: Response<UIImage, NSError> -> Void) -> Self {
return response(responseSerializer: Request.imageResponseSerializer(), completionHandler: completionHandler)
}
}

Alamofire Use of undeclared type 'Serializer'

I have updated to XCode 7 beta 6 and Alamofire needed to be updated to beta 3. In doing so, I'm having to update areas of the code that use Alamofire. One area in particular that I'm having difficulty updating is the code which is used to retrieve an image from a specified URL and load it into a UIImageView.
Previously, the extension for Alamofire that handled that was:
extension Alamofire.Request {
class func imageResponseSerializer() -> Serializer {
return { request, response, data in
if data == nil {
return (nil, nil)
}
let image = UIImage(data: data!, scale: UIScreen.mainScreen().scale)
return (image, nil)
}
}
func responseImage(completionHandler: (NSURLRequest, NSHTTPURLResponse?, UIImage?, NSError?) -> Void) -> Self {
return response(serializer: Request.imageResponseSerializer(), completionHandler: { (request, response, image, error) in
completionHandler(request!, response, image as? UIImage, error)
})
}
}
But not that is throwing the error
Use of undeclared type 'Serializer'
I do realize that Alamofire doesn't use Serializer anymore, but does anyone know where I can find some documentation or examples what to do now when retrieving images?
As you can find in the readme the serialization was rewritten.
You shoudl be able to use the method below:
public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Request {
public func responseObject<T: ResponseObjectSerializable>(completionHandler: Response<T, NSError> -> Void) -> Self {
let responseSerializer = ResponseSerializer<T, NSError> { request, response, data, error in
guard error == nil else { return .Failure(error!) }
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data, error)
switch result {
case .Success(let value):
if let
response = response,
responseObject = T(response: response, representation: value)
{
return .Success(responseObject)
} else {
let failureReason = "JSON could not be serialized into response object: \(value)"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(error)
}
case .Failure(let error):
return .Failure(error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
UIImage serializer for Alamofire, updated for Alamofire 2.0 and Swift 2
Alamofire 2.0 and Swift 2.0

Resources