Alamofire custom reponse migration from Alamofire v1.3 to 3.0 (and Swift 2 syntax) - swift2

I am converting an project from Swift 1.1 to Swift 2.0 that used Alamofire 1.3.
Because this version of Alamofire was not compatible with Swift 2.0, I switched to the very last version of Alamofire (3.1.x).
However this broke the code, I am now getting the error message
"Cannot call value of non-function type 'NSHTTPURLResponse?'"
which is due to my my extension to create a custom "responseShop" Alamofire.Request.
How can this Alamofire.Request extension correctly be converted to the Alamofire 3.x/Swift 2.0 syntax?
extension Alamofire.Request {
func responseShop(options: NSJSONReadingOptions = .AllowFragments, var errorHandler:ProtocolWebServiceErrorHandler?, completionHandler: (ShopCallResult?, WebServiceErrorCode) -> Void ) -> Self {
objc_sync_enter(communicationLockObj)
return response(serializer: Request.JSONResponseSerializer(options: options), completionHandler: {
(request, response, JSON, error) in
log.verbose("\(JSON)")
//network error?
if let error = error {
//is it cancelled?
if error.code == -999 {
dispatch_async(dispatch_get_main_queue()) {
//call handler with cancelled code
completionHandler(nil, WebServiceErrorCode.requestCancelled)
}
objc_sync_exit(communicationLockObj)
return
}
dispatch_async(dispatch_get_main_queue()) {
errorHandler?.handleWebServiceError(WebServiceErrorCode.connectError, errorText : error.localizedDescription, request: request, json: JSON)
//call and supply org error
completionHandler(nil, WebServiceErrorCode.connectError)
}
objc_sync_exit(communicationLockObj)
return
}
if JSON == nil {
dispatch_async(dispatch_get_main_queue()) {
errorHandler?.handleWebServiceError(WebServiceErrorCode.jsonNil, errorText: nil, request: request, json: JSON)
//call and supply org error
completionHandler(nil, WebServiceErrorCode.jsonNil)
}
objc_sync_exit(communicationLockObj)
return
}
//api return error?
let callResult = ShopCallResult(json: JSON!)
if callResult.statusCode.failed {
dispatch_async(dispatch_get_main_queue()) {
errorHandler?.handleWebServiceError(callResult.statusCode, errorText: callResult.statusCode.localizedText, request: request, json: JSON)
completionHandler(callResult, callResult.statusCode)
}
objc_sync_exit(communicationLockObj)
return
}
//no error
dispatch_async(dispatch_get_main_queue()) {
completionHandler(callResult, WebServiceErrorCode.OK)
}
objc_sync_exit(communicationLockObj)
})
return self
}
}

Based on the feedback of #ProblemSolver I managed to convert the code, now it looks like this:
extension Alamofire.Request {
func responseShop(queue: dispatch_queue_t? = nil, options: NSJSONReadingOptions = .AllowFragments, errorHandler:ProtocolWebServiceErrorHandler?, completionHandler: (ShopCallResult?, WebServiceErrorCode) -> Void ) -> Self {
//enter thread protected area...
objc_sync_enter(communicationLockObj)
return responseJSON() {
response in
switch response.result {
case .Success(let JSON):
//log json in verbose mode
log.verbose("\(JSON)")
//parse the returned json
let callResult = ShopCallResult(json: JSON)
//is it failed?
if callResult.statusCode.failed {
//call supplied error handler on the main thread
dispatch_async(dispatch_get_main_queue()) {
errorHandler?.handleWebServiceError(callResult.statusCode, errorText: callResult.statusCode.localizedText, request: self.request!, json: JSON)
completionHandler(callResult, callResult.statusCode)
}
//release the lock
objc_sync_exit(communicationLockObj)
//processing done!
return
}
//no error call handler on main thread
dispatch_async(dispatch_get_main_queue()) {
completionHandler(callResult, WebServiceErrorCode.OK)
}
//release the lock
objc_sync_exit(communicationLockObj)
case .Failure(let error):
//WARNING: cancelled is still error code 999?
//is it cancelled?
if error.code == -999 {
//just call the completion handler
dispatch_async(dispatch_get_main_queue()) {
//call handler with cancelled code
completionHandler(nil, WebServiceErrorCode.requestCancelled)
}
//release the lock
objc_sync_exit(communicationLockObj)
//stop furhter processing
return
}
//error with the json?
if error.code == Alamofire.Error.Code.JSONSerializationFailed .rawValue {
//call the error handler
dispatch_async(dispatch_get_main_queue()) {
errorHandler?.handleWebServiceError(WebServiceErrorCode.jsonNil, errorText: nil, request: self.request!, json: nil)
//call and supply org error
completionHandler(nil, WebServiceErrorCode.jsonNil)
}
//release the lock
objc_sync_exit(communicationLockObj)
//stop further processing
return
}
//must be some other kind of network error
dispatch_async(dispatch_get_main_queue()) {
log.error("\(error)")
//so call the error handler
errorHandler?.handleWebServiceError(WebServiceErrorCode.connectError, errorText : error.localizedDescription, request: self.request!, json: nil)
//call and supply org error
completionHandler(nil, WebServiceErrorCode.connectError)
}
//release the lock
objc_sync_exit(communicationLockObj)
}
}
}
}

Related

Webclient retryWhen and onErrorResume mutually exclusive?

I am trying to implement a retry on specific exception but I could not make it work using the following:
return client
.sendWebhook(request, url)
.exchangeToMono(
response -> {
final HttpStatus status = response.statusCode();
return response
.bodyToMono(String.class)
.defaultIfEmpty(StringUtils.EMPTY)
.map(
body -> {
if (status.is2xxSuccessful()) {
log.info("HTTP_SUCCESS[{}][{}] body[{}]", functionName, company, body);
return ResponseEntity.ok().body(body);
} else {
log.warn(
format(
"HTTP_ERROR[%s][%s] status[%s] body[%s]",
functionName, company, status, body));
return status.is4xxClientError()
? ResponseEntity.badRequest().body(body)
: ResponseEntity.internalServerError().body(body);
}
});
})
.retryWhen(
Retry.backoff(1, Duration.ofSeconds(1))
.filter(
err -> {
if (err instanceof PrematureCloseException) {
log.warn("PrematureCloseException detected retrying.");
return true;
}
return false;
}))
.onErrorResume(
ex -> {
log.warn(
format(
"HTTP_ERROR[%s][%s] errorInternal[%s]",
functionName, company, ex.getMessage()));
return Mono.just(ResponseEntity.internalServerError().body(ex.getMessage()));
});
It seems that the retry is never getting called on PrematureCloseException.
Resolved, it was not working because of rootCause
Retry.backoff(3, Duration.ofMillis(500))
.filter(
ex -> {
if (ExceptionUtils.getRootCause(ex) instanceof PrematureCloseException) {
log.info(
"HTTP_RETRY[{}][{}] PrematureClose detected retrying", functionName, company);
return true;
}
return false;
});

How parse id with SwiftyJSON swift 4.2 ,why is wrong?

//This JSON {"data":[{"id":288,"eid":16,"admin":true},{"id":289,"eid":16,"admin":false}],"meta":{"count":2}}
Alamofire.request(self.url, headers: header).responseJSON
(completionHandler: { response in
statusCode = (response.response?.statusCode)!
if statusCode != 200{
}else{
switch response.result {
case .success( let responseJSON):
let json = JSON(responseJSON)
print(json)
let data = json["data"]
print(data)
case .failure(_):
print("ERROR")
}
}
})
}
}
}

Xcode : Alamofire get String response

I am new in IOS development and currently learning networking with Alamofire
i am trying to make a login ...
whenever the credentials are correct the .php file returns a json and i am able to get that json from Alamofire through the following code:
Alamofire.request(loginUrl, method: .post, parameters: parameters).responseJSON { (response:DataResponse<Any>) in
print("String:\(response.result.value)")
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(self.loginUrl)
print(data)
}
case .failure(_):
print(self.loginUrl)
print("failed")
print("Error message:\(response.result.error)")
break
}
}
now...when ever the credentials are wrong, the .php does't give the json..instead it return a string ..for example "wrong_password" or "userLocked" etc etc...
how can i get the String response through Alamofire?
If you want JSON response use .responseJSON , if you want String response use .responseString. If you want both use both. Hope this help.
Alamofire.request(loginUrl, method: .post, parameters: parameters)
.responseJSON { response in
print("JSON:\(response.result.value)")
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(data)
}
case .failure(_):
print("Error message:\(response.result.error)")
break
}
}
.responseString { response in
print("String:\(response.result.value)")
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(data)
}
case .failure(_):
print("Error message:\(response.result.error)")
break
}
}
UPDATED: Swift 5, Alamofire 5
AF.request(urlString, method: .post, parameters: parameters)
.responseJSON { response in
print("response: \(response)")
switch response.result {
case .success(let value):
print("value**: \(value)")
case .failure(let error):
print(error)
}
}
.responseString { response in
print("response: \(response)")
switch response.result {
case .success(let value):
print("value**: \(value)")
case .failure(let error):
print(error)
}
}
I resolve this by:
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
source:
https://github.com/Alamofire/Alamofire/issues/818

Working using swift and logInWithPublishPermissions

I have this code:
let login: FBSDKLoginManager = FBSDKLoginManager()
login.logInWithPublishPermissions(["publish_actions"], handler: { (result: FBSDKLoginManagerLoginResult!, error: NSError!) -> Void in
if error != nil {
NSLog(error.localizedFailureReason!)
} else if result.isCancelled {
NSLog("Canceled")
} else if result.grantedPermissions.contains("publish_actions") {
self.loginFacebookButtin.hidden = true
}
})
This code worked ok, but I have this warning message:
'logInWithPublishPermissions(_:handler:)' is deprecated: use logInWithPublishPermissions:fromViewController:handler: instead
I tried to fix this warning but I could not. Someone knows how to fix it?
According to the FBSDK API:
The way you're using the method is deprecated. It wants you to use the new way it indicated in its documentation, as seen below:
- (void)
logInWithPublishPermissions: (NSArray *)permissions
handler: (FBSDKLoginManagerRequestTokenHandler)handler
__attribute__((deprecated("use logInWithPublishPermissions: fromViewController:handler: instead")));
Therefore you would use it like so:
let login: FBSDKLoginManager = FBSDKLoginManager()
login.logInWithPublishPermissions(["publish_actions"], fromViewController: self, handler: { (response: FBSDKLoginManagerLoginResult!, error: NSError!) in
if (error != nil) {
NSLog(error.localizedFailureReason!)
} else if result.isCancelled {
NSLog("Canceled")
} else if result.grantedPermissions.contains("publish_actions") {
self.loginFacebookButtin.hidden = true
}
})
You need to call the function like this:
let login: FBSDKLoginManager = FBSDKLoginManager()
login.logInWithPublishPermissions(["publish_actions"], fromViewController: self, handler: { (result: FBSDKLoginManagerLoginResult!, error: NSError!) -> Void in
if error != nil {
NSLog(error.localizedFailureReason!)
} else if result.isCancelled {
NSLog("Canceled")
} else if result.grantedPermissions.contains("publish_actions") {
self.loginFacebookButtin.hidden = true
}
})

NSURL error for broken links in Swift

I coded a function for OSX 10.10 that is willing to open a text file from an URL and display its content.
Everything is working but if the URL cannot be reach then the App will crash. How could I handle this type of Error?
I guess it comes from the completionHandler closure but I am not sure.
here is my code
#IBAction func checkAdminMessage(sender: NSMenuItem) {
let messageURL = NSURL(string: "http://www.xxxxxx.com/text.txt")
// The Network stuff will be handled in a background thread
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(messageURL!,
completionHandler: {
(location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
var urlContents = NSString(contentsOfURL: location, encoding: NSUTF8StringEncoding, error: nil)
// Check if text.txt has NULL as content
if urlContents! == "NULL" {
// Have to use Grand Central Dispatch to put NSAlert in the main thread
let noMessage = NSLocalizedString("Nothing there", comment: "Text to dislay when the file is empty" )
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.displayAlertNotification(notification: noMessage)
}
} else {
// If the file is not empty then we display the content of this file
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.displayAlertNotification(notification: urlContents!)
}
}
})
downloadTask.resume()
}
Thank you
EDIT: Here is the updated code but the App still crashed
#IBAction func checkAdminMessage(sender: NSMenuItem) {
if let messageURL = NSURL(string: "http://www.xxxxxx.com/text.txt") {
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(messageURL,
completionHandler: {
(location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
var urlContents = NSString(contentsOfURL: location, encoding: NSUTF8StringEncoding, error: nil )
if urlContents == "NULL" {
println(urlContents)
// Have to use Grand Central Dispatch to put NSAlert in the main thread
let noMessage = NSLocalizedString("Nothing there", comment: "Text to dislay when the file is empty" )
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.displayAlertNotification(notification: noMessage)
}
}
else {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.displayAlertNotification(notification: urlContents!)
}
}
})
downloadTask.resume()
}
else {
println("Error")
}
}
NSURL(string: ...) returns an optional, so the result may be nil due to several reasons.
Wrap your code in a conditional unwrap:
if let messageURL = NSURL(string: "http://www.xxxxxx.com/text.txt") {
// success
...
}
else {
// error
}
I figured it out with the helps of the people that commented my question.
I was getting a nil from 'location' in downloadTaskWithUrl, then the var urlContents was receiving a nil as well.
The solution is to check if 'location' is nil :
let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(messageURL,
completionHandler: {
(location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
**if (location != nil) {**
var urlContents = NSString(contentsOfURL: location, encoding: NSUTF8StringEncoding, error: nil ) ...

Resources