UPDATED Question:
At first my issue was about assigning a custom ParameterEncoding per ViewController based on the HTTP.Method request, I found a solution and added the string in the Alamofire.request then added import Alamofire to the head of each ViewController which helped calling JSONEncoding and URLEncoding and changed the way of call by adding the header to the request as well to avoid 401 unauthorized error.
func callingHttpRequest(params:Dictionary<String,Any>, apiname:String,cuurentView:UIViewController,method:HTTPMethod, taskCallback: #escaping (Int,
AnyObject?) -> Void) {
let urlString = HOST_NAME + apiname
print("url",urlString)
print("params", params)
Alamofire.request(urlString,method: method,parameters:params).validate().responseJSON { response in
switch response.result {
case .success(let resultData):
taskCallback(1,resultData as AnyObject)
let returnData = String(data: response.data! , encoding: .utf8)
print("returnData" ,returnData!)
print("request URL", response.request!)
break
case .failure(let error):
let returnData = String(data: response.data! , encoding: .utf8)
print("returnData" ,returnData!)
print("request URL", response.request!)
if !Connectivity.isConnectedToInternet(){
NetworkManager.sharedInstance.dismissLoader()
cuurentView.view.isUserInteractionEnabled = true
let AC = UIAlertController(title: "Warning", message: error.localizedDescription, preferredStyle: .alert)
let okBtn = UIAlertAction(title: "Retry", style: .default, handler: {(_ action: UIAlertAction) -> Void in
taskCallback(2, "" as AnyObject)
})
let noBtn = UIAlertAction(title: "Cancel", style: .destructive, handler: {(_ action: UIAlertAction) -> Void in
})
AC.addAction(okBtn)
AC.addAction(noBtn)
cuurentView.present(AC, animated: true, completion: { _ in })
}
else{
let errorCode:Int = error._code;
if errorCode != -999 && errorCode != -1005{
NetworkManager.sharedInstance.dismissLoader()
cuurentView.view.isUserInteractionEnabled = true
let AC = UIAlertController(title: "Warning", message: error.localizedDescription, preferredStyle: .alert)
let okBtn = UIAlertAction(title: "Retry", style: .default, handler: {(_ action: UIAlertAction) -> Void in
taskCallback(2, "" as AnyObject)
})
let noBtn = UIAlertAction(title: "Cancel", style: .destructive, handler: {(_ action: UIAlertAction) -> Void in
})
AC.addAction(okBtn)
AC.addAction(noBtn)
cuurentView.present(AC, animated: true, completion: { _ in })
}else if errorCode == -1005{
NetworkManager.sharedInstance.dismissLoader()
taskCallback(2, "" as AnyObject)
}
}
break;
}
}
Now what's really pissing me off is the response of the request, the app is made with user login so each time the app runs it will check if the user logged in or not. When the HTTP request is sent the response returns with SQL Query added to JSON if the user is logged in as below
Failure returnData string(84) "SELECT * FROM customer where LOWER(user) = 'helloworld' AND status = '1'"
{"success":true,"data":[{,,,,,"}
This is causing a failure response and and error
Warning: JSON could not be serialized because of error: The data couldn't be read because it isn't in the correct format.
This is really insane why the response is returning a SQL Query while it shouldn't. That wasn't happening before I customized the header and encoding of the Alamofire.request.
Any way faced such issue can hep please!
P.S.: The response has 200 OK HTTP Response but with failure Data Response
Related
I'm working on a banking app and I'd like to display alert message when a bank account is in collections (negative balance). I'd like to combine the success and failure case in one case and perhaps a way to refactor/clean the following code. The failure case (if the API Call fails) uses the Hardcoded strings for the Alert. The success case uses and retrieves strings from an API Call.
I'd like to know if I can combine the success and failure case in one case to keep it more clean, if possible. Thank you for your help.
private func checkBankAccountIsInCollections() -> Bool {
guard let accountModel = accountController.accountControllerViewModel?.accountModel else { return false }
let isAccountIsInCollections = accountModel.isAccountInCollections
if isAccountIsInCollections {
accountManager.getAPIContent { [weak self] result in
guard let self = self else { return }
switch result {
case .failure:
let alertWithNoAPIContentController = UIAlertController(
title: InternalStrings.collectionHeader,
message: InternalStrings.collectionMessage,
preferredStyle: .alert
)
let okAction = UIAlertAction(title: InternalStrings.collectionHeader.buttonTitle, style: .cancel) { _ in }
alertWithNoAPIContentController(okAction)
self.present(alertWithNoAPIContentController, animated: true, completion: nil)
case let .success(ContentModel):
let collectionsAPIContent = ContentModel.collectionsAccountElements
let alertWithAPIContentController = UIAlertController(
title: collectionsAPIContent?.header,
message: collectionsAPIContent?.description,
preferredStyle: .alert
)
let okAction = UIAlertAction(title: collectionsAPIContent.buttonTitle, style: .cancel) { _ in }
alertWithAPIContentController.addAction(okAction)
self.present(alertWithAPIContentController, animated: true, completion: nil)
}
}
}
I am new to swift . I have developed a login form which verifies data from mysql database and for that I have used json and swift code . But there is an issue in my code , after providing the login details when I click on the submit button .It shows the alert view that the credentials are invalid ,even after providing the correct credentials . I have attached the code below . Please if anyone can help me
class ViewController: UIViewController {
#IBOutlet weak var PASSWORD: UITextField!
#IBOutlet weak var USERNAME: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func submitbtn(_ sender: Any) {
let username: NSString = self.USERNAME.text! as NSString
let password: NSString = self.PASSWORD.text! as NSString
if username.isEqual(to: "") || password.isEqual(to: ""){
let myAlert = UIAlertController(title: "Alert", message:"All fields are required to fill in", preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
// return
}
else
{
let post:NSString = "UserName\(username)&PassWord\(password)" as NSString
NSLog("PostData : %d", post)
let url = "http://demo.talentclouds.in/API/LoginHandler.asmx/Login?username=admin#penn.in&password=123"
let postData:NSData = post.data(using: String.Encoding.ascii.rawValue)! as NSData
let postLength:NSString = String ( postData.length ) as NSString
let request = NSMutableURLRequest(url: NSURL(string: url)! as URL)
request.httpMethod = "POST"
request.httpBody = postData as Data
request.setValue(postLength as String, forHTTPHeaderField: "Content-Length")
request.setValue("application/x-www-form-urlencoder", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
// let responseError:NSError?
// let response:URLResponse?
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
DispatchQueue.main.async {
if(error != nil)
{
//Display an alert message
let myAlert = UIAlertController(title: "Alert", message: error!.localizedDescription, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
}
//parsing the response
do {
//converting resonse to NSDictionary
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let username = parseJSON["username"] as? String
if(username != nil)
{
UserDefaults.standard.set(parseJSON["username"], forKey: "username")
UserDefaults.standard.set(parseJSON["password"], forKey: "password")
UserDefaults.standard.synchronize()
// let username : NSInteger = json?.value(forKey: username as String)as! NSInteger
// NSLog("Success : %ld ", username)
// if (username != nil)
// {
print("Login OK")
}
else{
print("Login Failed")
let alert = UIAlertController(title: "Invalid", message: "Invalid Credentials", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
catch {
print("Login Failed")
let alert = UIAlertController(title: "Error", message: "Please check your internet connection", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
})
//executing the task
task.resume()
}
}
}
Your issue there
let username = parseJSON["username"] as? String
It should be read profile dictionary first
if let profile = parseJSON["Profile"] as? [String:Any],
let username = profile["username"] as? String
Here Full code:
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
DispatchQueue.main.async {
if(error != nil)
{
//Display an alert message
let myAlert = UIAlertController(title: "Alert", message: error!.localizedDescription, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:nil)
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
}
//parsing the response
do {
//converting resonse to NSDictionary
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
if let profile = parseJSON["Profile"] as? [String:Any],
let username = profile["username"] as? String
{
UserDefaults.standard.set(parseJSON["username"], forKey: "username")
UserDefaults.standard.set(parseJSON["password"], forKey: "password")
UserDefaults.standard.synchronize()
// let username : NSInteger = json?.value(forKey: username as String)as! NSInteger
// NSLog("Success : %ld ", username)
// if (username != nil)
// {
print("Login OK")
}
else{
print("Login Failed")
let alert = UIAlertController(title: "Invalid", message: "Invalid Credentials", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
catch {
print("Login Failed")
let alert = UIAlertController(title: "Error", message: "Please check your internet connection", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
})
//executing the task
task.resume()
}
}
}
I've this code to take the X-Transmission-Session-Id but now i need to resend the request with the updated header.
function takeXTransmissionSessionId( ){
let urls = NSURL(string: "\(url)")
let task = NSURLSession.sharedSession().dataTaskWithURL(urls!) { (data, respornse, error) -> Void in
guard error == nil && data != nil else {
print("error=\(error!)")
let alertView = UIAlertController(title: "ERROR", message: "A server with the specified hostname could not be found.", preferredStyle: UIAlertControllerStyle.Alert)
let actionView = UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil)
alertView.addAction(actionView)
self.presentViewController(alertView, animated: true, completion: nil)
return
}
if let httpStatus = respornse as? NSHTTPURLResponse where httpStatus.statusCode != 200 {
let sesionID = httpStatus.allHeaderFields["X-Transmission-Session-Id"]
if sesionID == nil {
let alertView = UIAlertController(title: "ERROR", message: "The request has not been applied because it lacks valid authentication credentials for the target resource.", preferredStyle: UIAlertControllerStyle.Alert)
let actionView = UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil)
alertView.addAction(actionView)
self.presentViewController(alertView, animated: true, completion: nil)
}else{
//print("\(respornse!)")
//print("\(sesionID!)")
self.XTransmissionSessionId = "\(sesionID!)"
}
}
}
task.resume()
}
My problem is i tray many times in a different ways but i don't know what i need to do.
Thanks!
This is the code for do what i need:
request.HTTPMethod = "POST"
request.addValue("\(XTransmissionSessionId)", forHTTPHeaderField: "X-Transmission-Session-Id")
I am using swift to send a message to my server, however, I am not able to get an alert popup to happen when it is over. Here is the code.
func sendSimpleCommand(siteId: Int, command: String) -> Int {
Alamofire.request(.GET, commandUrl, parameters: ["site": siteId, "command": command, "device": "ios"])
.responseJSON { response in
//print(response.result) // result of response serialization
switch response.result {
case .Success(_):
print("success code back from api server for command sent")
let alertView = UIAlertController(title: "Command Sent", message: "Your \(command) has been sent.", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
case .Failure(_):
print("FAIL code back from api server for command sent")
let alertView = UIAlertController(title: "Connect Error", message: "Network error, please try again", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
}
}
return 1
}
#IBAction func startButtonTouch(sender: UIButton) {
let helper = HelperActions()
let site = ActiveSite.sharedInstance.siteObject
let command: String = "start"
sendSimpleCommand(site.id , command: command)
}
Now when I run it, the network communication happens correctly but then I get an error and the alert window never shows up.
Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior
Just add this single line on top of your code to make an global request of UIAlertController.
As in swift we don't have to deallocate any views. Swift language handels it on their side.
let alertView : UIAlertController?
remove all declaration of alertView in the class
Edit
func sendSimpleCommand(siteId: Int, command: String) -> Int {
Alamofire.request(.GET, commandUrl, parameters: ["site": siteId, "command": command, "device": "ios"])
.responseJSON { response in
//print(response.result) // result of response serialization
switch response.result {
case .Success(_):
print("success code back from api server for command sent")
alertView = UIAlertController(title: "Command Sent", message: "Your \(command) has been sent.", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
case .Failure(_):
print("FAIL code back from api server for command sent")
alertView = UIAlertController(title: "Connect Error", message: "Network error, please try again", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
}
}
return 1
}
#IBAction func startButtonTouch(sender: UIButton) {
let helper = HelperActions()
let site = ActiveSite.sharedInstance.siteObject
let command: String = "start"
sendSimpleCommand(site.id , command: command)
}
I've been trying to get information out of a server call. Which already works fine, but when I want to use the information to make a dialogue box appear it doesn't really work. It goes too fast to the next line. The only way I could make it work is by delaying the next bit in the code but considering it's a server call I can't determine how long it'll always take. I tried using dispatch_sync but it didn't work at all.
func logIn(username: String, password: String) -> Void {
var error: NSError?
var call = "api/usersession/"
var login = "username=" + username + "&password=" + password
API().getLogin(login, api:call, { (data) -> Void in
let json = JSON(data: data, error: &error)
println(json.self)
let status = json["status"].stringValue!
if (status == "1") {
alertController = UIAlertController(title: "Something went wrong", message: json["result"].stringValue, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
} else {
alertController = UIAlertController(title: "Welcome!", message: "You're signed in", preferredStyle: UIAlertControllerStyle.Alert)
}
})
}
I believe that whenever the code gets to the "getLogin" part it just immediately goes on to return whatever it has (which is always nothing). When I say that self.presentViewController needs to delay by an amount then it does work, but this would make the app feel a bit clunky.
Edit:
func getLogin(login: String, api: String, success: ((apiData: NSData!) -> Void)) {
var request = NSMutableURLRequest(URL: NSURL(string: website + api)!)
var learn = API()
var postString = login
request.HTTPMethod = "POST"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
learn.httpRequest(request, callback:{(data, error) -> Void in
if let urlData = data {
success(apiData: urlData)
}
})
}
And httpRequest:
func httpRequest(request: NSURLRequest!, callback: (NSData?,
String?) -> Void) {
var configuration =
NSURLSessionConfiguration.defaultSessionConfiguration()
var userPassWordString = apiusername + ":" + apipassword
let userPasswordData = userPassWordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCrendtial = userPasswordData!.base64EncodedStringWithOptions(nil)
let authString = "Basic \(base64EncodedCrendtial)"
configuration.HTTPAdditionalHeaders = ["Authorization": authString]
var session = NSURLSession(configuration: configuration,
delegate: self,
delegateQueue:NSOperationQueue.mainQueue())
var task = session.dataTaskWithRequest(request){
(data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
if error != nil {
callback(nil, error.localizedDescription)
} else {
var result = NSData(data: data)
callback(result, nil)
}
}
task.resume()
}
It goes too fast to the next line.
You need to think about asynchronous operations. When you do something that's going to take time, whether it's making a network request to a server or asking the user to provide some information, you don't just make a function call and expect the results to show up immediately. Instead, you call a function or method that starts the process, and then you go off and do other things until the process completes. For a network request, that usually means that you provide a delegate object or a completion block that gets called when the connection has new information. When dealing with the user, you might put up a dialog box and leave it at that -- the process continues when the user triggers an action by tapping some button or filling in some field.
I managed to fix it by making the UIAlertController present itself from the function itself like so:
if (status == "1") {
alertController = UIAlertController(title: "Er ging iets fout", message: json["result"].stringValue, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController,animated: true, completion:nil)
} else {
alertController = UIAlertController(title: "Welcome!", message: "You're signed in!", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController,animated: true, completion:nil)
}