Cannot specialize non-generic type ResponseSerializer - swift2

From the documentation and the 2.0 Migrate Guide I tried to use Response Serialization but I'm having the following errors. I can't seem to figure out the problems. I'm also having the same errors with ResponseCollectionSerializable.

You should use GenericResponseSerializer that conforms to ResponseSerializer:
public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Request {
public func responseObject<T: ResponseObjectSerializable>(completionHandler: (NSURLRequest?, NSHTTPURLResponse?, Result<T>) -> Void) -> Self {
let responseSerializer = GenericResponseSerializer<T> { request, response, data in
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data)
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(data, error)
}
case .Failure(let data, let error):
return .Failure(data, error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
ResponseSerializer is the protocol in which all response serializers must conform to.

Related

Swift 3 - Invalid conversion from throwing function type '(Any) -> Void'

I'm new to swift and
I'm not understanding why I'm getting this error.
I've being reading similar questions and so far none of them solved this error or I have not found it:
Invalid conversion from throwing function of type '(_) throws -> ()'
to non-throwing function type '(Any) -> ()'
At the line:
self.ws.event.message = { message in
The piece of code with the error:
public var ws = WebSocket()
public func websocket(token: Any){
self.ws.open("ws://"+String(APIHOST)+":"+String(port)+"/ws?token="+String(describing: token))
self.ws.event.message = { message in
if let text = message as? String {
let json = try JSONSerialization.jsonObject(with: text, options: []) as? [String: Any]
print("recv: \(text)")
}
}
}
Thanks for any help
Try below piece of code
public var ws = WebSocket()
public func websocket(token: Any){
self.ws.open("ws://"+String(APIHOST)+":"+String(port)+"/ws?token="+String(describing: token))
self.ws.event.message = { message in
if let dataObj = message as? Data {
do {
let json = try JSONSerialization.jsonObject(with:dataObj, options: []) as? [String: Any]
print("recv: \(text)")
} catch error {
print("Unable to load data: \(error)")
}
}
}
}
If you have a function that throws something, it usually means there might be a chance of error when accessing that data in your case JSON.
If function throws you need to do {} catch {} to tell Swift you are going to handle an error.

What does [weak self] do and what is this code structure means?

I have couple of questions about the structure of the following code.I assume progressBlock and completionhandlers are callback functions passed to downloadWithDownloadType function. Is my assumption correct? And What does [weak Self] before function parameters do? In what situation do you need that?
func downloadContent(key: String, pinOnCompletion: Bool) {
let manager = AWSUserFileManager.defaultUserFileManager()
let content = manager.contentWithKey(self.prefix + key)
content.downloadWithDownloadType(
.IfNewerExists,
pinOnCompletion: pinOnCompletion,
progressBlock: {[weak self](content: AWSContent?, progress: NSProgress?) -> Void in
guard self != nil else { return }
/* Show progress in UI. */
},
completionHandler: {[weak self](content: AWSContent?, data: NSData?, error: NSError?) -> Void in
guard self != nil else { return }
if let error = error {
// Handle Error
return
}
if let fileData = data {
let rawData = NSString(data: fileData, encoding:NSUTF8StringEncoding) as! String
// Do something
}
//Download Complete
})
}

Swift 3, URLSession dataTask completionHandler not called

I am writing a library, So not using UIKit, Even in my iOS app same code works, but when i execute in command line in doesn't . In PlayGround also it seems working.
For some reason callback is not getting triggered, so print statements are not executing.
internal class func post(request: URLRequest, responseCallback: #escaping (Bool, AnyObject?) -> ()) {
execTask(request: request, taskCallback: { (status, resp) -> Void in
responseCallback(status, resp)
})
}
internal class func clientURLRequest(url: URL, path: String, method: RequestMethod.RawValue, params: Dictionary<String, Any>? = nil) -> URLRequest {
var request = URLRequest(url: url)
request.httpMethod = method
do {
let jsonData = try JSONSerialization.data(withJSONObject: (params! as [String : Any]), options: .prettyPrinted)
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
} catch let error as NSError {
print(error)
}
return request
}
private class func execTask(request: URLRequest, taskCallback: #escaping (Bool,
AnyObject?) -> ()) {
let session = URLSession(configuration: URLSessionConfiguration.default)
print("THIS LINE IS PRINTED")
let task = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in
if let data = data {
print("THIS ONE IS NOT PRINTED")
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
taskCallback(true, json as AnyObject?)
} else {
taskCallback(false, json as AnyObject?)
}
}
})
task.resume()
}
Edits -: I am writing a library, So not using UIKit, Even in my iOS app same code works, but when i execute in command line in doesn't . In PlayGround also it seems working.
I made a simple App from scratch. (Xcode 8 beta 6 / swift 3)
In controller I pasted Your code. (plus url creation..)
I see all in debugger:
THIS ONE IS PRINTED
THIS ONE IS PRINTED, TOO
I AM BACK
so it seems workin.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let URLString = "https://apple.com"
let url = URL(string: URLString)
let request = URLRequest(url: url!)
ViewController.execTask(request: request) { (ok, obj) in
print("I AM BACK")
}
}
private class func execTask(request: URLRequest, taskCallback: #escaping (Bool,
AnyObject?) -> ()) {
let session = URLSession(configuration: URLSessionConfiguration.default)
print("THIS LINE IS PRINTED")
let task = session.dataTask(with: request, completionHandler: {(data, response, error) -> Void in
if let data = data {
print("THIS ONE IS PRINTED, TOO")
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
taskCallback(true, json as AnyObject?)
} else {
taskCallback(false, json as AnyObject?)
}
}
})
task.resume()
}
}
I know its late for the answer but in case you have not figure out the issue or getting issue at other places, lets try this.
You need to save session variable outside method scope (make it a instance variable). Since you defined it locally in function scope. Its get deallocated before completion handler can be called, remember completion handler can't retain your session object and after execution of run loop, garbage collector will dealloc your session object. We need to retain such objects whenever we want call back from delegates or from completion handler..
self.session = URLSession(configuration: URLSessionConfiguration.default)
Did the changes suggested here, It works now.
Using NSURLSession from a Swift command line program
var sema = DispatchSemaphore( value: 0 )
private func execTask(request: URLRequest, taskCallback: #escaping (Bool,
AnyObject?) -> ()) {
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil )
session.dataTask(with: request) {(data, response, error) -> Void in
if let data = data {
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
taskCallback(true, json as AnyObject?)
} else {
taskCallback(false, json as AnyObject?)
}
}
}.resume()
sema.wait()
}
let dataTask = session.dataTask(with: request, completionHandler: {data, response,error -> Void in
print("Request : \(response)")
let res = response as! HTTPURLResponse
print("Status Code : \(res.statusCode)")
let strResponse = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Response String :\(strResponse)")
})
dataTask.resume()
Swift 3.0
Just copy below code into your view controller.
#IBAction func btnNewApplicationPressed (_ sender: UIButton) {
callWebService()
}
func callWebService() {
// Show MBProgressHUD Here
var config :URLSessionConfiguration!
var urlSession :URLSession!
config = URLSessionConfiguration.default
urlSession = URLSession(configuration: config)
// MARK:- HeaderField
let HTTPHeaderField_ContentType = "Content-Type"
// MARK:- ContentType
let ContentType_ApplicationJson = "application/json"
//MARK: HTTPMethod
let HTTPMethod_Get = "GET"
let callURL = URL.init(string: "https://itunes.apple.com/in/rss/newapplications/limit=10/json")
var request = URLRequest.init(url: callURL!)
request.timeoutInterval = 60.0 // TimeoutInterval in Second
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
request.httpMethod = HTTPMethod_Get
let dataTask = urlSession.dataTask(with: request) { (data,response,error) in
if error != nil{
return
}
do {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Result",resultJson!)
} catch {
print("Error -> \(error)")
}
}
dataTask.resume()
}
Sometimes, for me, the solution when completionHandler were not called in these cases was because the flag "Allow Arbitrary loads" on Info.plist was defined as NO.
Allow Arbitrary loads flag defined as YES

Nesting Alamofire callbacks or return value for Global Usage

I am currently trying to nest Alamofire requests to use data that I have already successfully received using GET requests.
For this piece of code I have used Rob's answer in this question
How to return value from Alamofire
However, I can not either nest the Alamofire requests or use them by separate.
This is what I am trying to do
override func viewDidLoad() {
super.viewDidLoad()
var currentFoodType: String = ""
var currentFoodList: String = ""
//debug
//this is how I get back the token from NSUserDefault
if let myToken = userDefaults.valueForKey("token"){
// calling method to get the user info
getUserInfo(myToken as! String)
// calling method to get the product type
func getFoodCategory(completionHandler: (NSDictionary?, NSError?) -> ()) {
getProductTypes(myToken as! String, completionHandler: completionHandler)
}
getFoodCategory() { responseObject, error in
// use responseObject and error here
let foodTypesJSON = JSON(responseObject!)
//to get one single food category
currentFoodType = (foodTypesJSON["types"][0].stringValue)
print(currentFoodType)
/////////////////////////////////////////
func getFoodsByCategory(completionHandler: (NSDictionary?, NSError?) -> ()) {
print("getting " + currentFoodType)
self.getProductsByType(myToken as! String, productType: currentFoodType, completionHandler: completionHandler)
}
getFoodsByCategory() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
return
}
}
Then the two other functions I am calling from there are very straight forward Alamofire requests with callbacks to the completionHandlers above
//GET THE PRODUCT TYPES FROM THE SERVER
func getProductTypes(myToken: String, completionHandler: (NSDictionary?, NSError?) -> ()) {
let requestToken = "Bearer " + myToken
let headers = ["Authorization": requestToken]
let getProductTypesEndpoint: String = BASE_URL + PRODUCT_TYPES
Alamofire.request(.GET, getProductTypesEndpoint, headers: headers)
.responseJSON{ response in
switch response.result {
case .Success(let value):
completionHandler(value as? NSDictionary, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}//END ALAMOFIRE GET responseJSON
}
The above function returns a single food like "Desserts" which will be used in the following function to GET all the desserts from the server
//GET THE PRODUCTS FROM THE SERVER GIVEN A CATEGORY
func getProductsByType(myToken: String, productType: String, completionHandler: (NSDictionary?, NSError?) -> ()){
let requestToken = "Bearer " + myToken
let headers = ["Authorization": requestToken]
let getProductTypesEndpoint: String = BASE_URL + PRODUCT_BY_TYPE + productType
Alamofire.request(.GET, getProductTypesEndpoint, headers: headers)
.responseJSON { response in
switch response.result {
case .Success(let value):
print("no errors")
let auth = JSON(value)
print("The pbt GET description is: " + auth.description)
completionHandler(value as? NSDictionary, nil)
case .Failure(let error):
print("there was an error")
completionHandler(nil, error)
}
}//END ALAMOFIRE GET responseJSON
}
and this works well because when I print within the getProductsByType function
using
print("The pbt GET description is: " + auth.description)
I get the JSON with all the products but the problem is in the viewDidload function where I am nesting the callbacks
getFoodsByCategory() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
the print within that bit is showing me that something is wrong so I can not parse my response as I desire.
Because I get the following
responseObject = nil; error = nil
So my guess is that there must a be a different method to nest these callbacks?
Take a look at chained promises from PromiseKit. This also works well with Alamofire:
func loadFoo() -> Promise<Bar> {
return Promise<Bar> { fulfill, reject in
Alamofire.request(.GET, "url")
.responseJSON { response in
switch response.result {
case .Success(let value):
let bar = Bar(fromJSON: value)
fulfill(bar)
case .Failure(let error):
reject(error)
}
}
}
}
// Usage
getBar()
.then { bar -> Void in
// do something with bar
}
.error { error in
// show error
}
This is very simple example, but you can find more relevant examples in documentation.

Swift URL Response is nil

I have created a custom DataManager class. Inside it I want to fetch data in a method and return an NSData object to convert to JSON afterwards.
I have tried to get the data using the completionHandler but no luck:
class func fetchData() -> NSData? {
var session = NSURLSession.sharedSession(),
result = NSData?()
let DataURL : NSURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(DataURL, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
result = data
})
sessionTask.resume()
return result
}
The dataTask runs asynchronously. That means that the completion handler closure will not be called by the time you return from fetchData. Thus, result will not have been set yet.
Because of this, you should not try to retrieve data synchronously from an asynchronous method. Instead, you should employ an asynchronous completion handler pattern yourself:
class func fetchData(completion: #escaping (Data?, Error?) -> Void) {
let session = URLSession.shared
let url = URL(string: "http://...file.json")!
let task = session.dataTask(with: url) { data, response, error in
completion(data, error)
}
task.resume()
}
And you'd call it like so:
MyClass.fetchData { data, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
// use `data` here; remember to dispatch UI and model updates to the main queue
}
// but do not try to use `data` here
...
FYI, for the original pre-Swift 3 syntax, see previous revision of this answer.

Resources