Proper use of DispatchQueue in swift login - swift

Im not using properly DispatchQueue function since I have to click 2-3 times in order to change screen, since the data dont load on time. I tried couple of positions in the code but Im always getting the same result.
What is a proper use?
Here is my code:
func startLogin() {
userNameData = userName.text!.trimmingCharacters(in: .whitespacesAndNewlines)
passwordData = password.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if userNameData == "" || passwordData == "" { return } else {
let parameters = "{\n\t\"user\": \"\(userNameData)\",\n\t\"password\": \"\(passwordData)\"\n}"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://someurl.io:18999/salesAPI/login")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
print("User no encontrado!")
return
}
print(String(data: data, encoding: .utf8)!)
// semaphore.signal()
let decoder = JSONDecoder()
do {
let jsonPetitions = try decoder.decode(Token.self, from: data)
token = jsonPetitions.access_token
let defaults = UserDefaults.standard
defaults.set(true, forKey: "didLogin")
defaults.set(userNameData, forKey: "userNameData")
defaults.set(passwordData, forKey: "passwordData")
defaults.set(token, forKey: "enterKey")
}
catch {
print("No Json output!!")
return
}
}
func changeScreen() {
// performSegue(withIdentifier: "switchScreens", sender: nil)
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constance.Storyboard.homeViewController) as? HomeViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
}
dispatchGroup.enter()
task.resume()
self.dispatchGroup.leave()
dispatchGroup.notify(queue: DispatchQueue.main) {
if token == "" {
self.errorLabel.alpha = 0.5
self.errorLabel.text = "Algun dato esta mal"
self.errorLabel.textColor = UIColor.red
print ("No Token! User or the pass is wrong")
} else {
changeScreen()
}
}
} // end User Login
}
The code is just part of it but all the important part are there

The dispatch group isn’t used correctly. But rather than trying to fix that, we should just remove it, as it’s unnecessary. Just move the code inside the notify block into the dataTask closure, after you parse the data.
For example:
func startLogin() {
userNameData = userName.text!.trimmingCharacters(in: .whitespacesAndNewlines)
passwordData = password.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if userNameData == "" || passwordData == "" { return }
let parameters = ["user": userNameData, "password": passwordData]
var request = URLRequest(url: URL(string: "https://someurl.io:18999/salesAPI/login")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = try! JSONEncoder().encode(parameters)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
print("User no encontrado!")
return
}
let decoder = JSONDecoder()
do {
let jsonPetitions = try decoder.decode(Token.self, from: data)
token = jsonPetitions.access_token
let defaults = UserDefaults.standard
defaults.set(true, forKey: "didLogin")
defaults.set(userNameData, forKey: "userNameData")
defaults.set(passwordData, forKey: "passwordData")
defaults.set(token, forKey: "enterKey")
DispatchQueue.main.async {
if token == "" {
self.errorLabel.alpha = 0.5
self.errorLabel.text = "Algun dato esta mal"
self.errorLabel.textColor = UIColor.red
print ("No Token! User or the pass is wrong")
} else {
self.changeScreen()
}
}
} catch {
print("No Json output!!")
return
}
}
task.resume()
}
func changeScreen() {
// performSegue(withIdentifier: "switchScreens", sender: nil)
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constance.Storyboard.homeViewController) as? HomeViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
}

Related

Why is this URLSession.datatask not working in Swift 5 for macos

I am trying to make my own DynamicIP updater as a command line tool so I can set it up to run as a launch agent. I thought this would be a pretty simple thing to do, but I am not getting anything when I run this bit of code.
main.swift:
import AppKit
let userName = "yourUserName"
let password = "yourPassword"
let domain = "yourDomainName"
let ftp = "ftp"
let www = "www"
let checkIPURL = URL(string: "https://svc.joker.com/nic/checkip")
let domainUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(domain)")
let ftpUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(ftp).\(domain)")
let wwwUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(www).\(domain)")
var ipAddress = ""
if let url = checkIPURL {
print("1 - \(url)")
var request = URLRequest(url: url)
print("2 - \(request.url!)")
request.httpMethod = "POST"
print("3")
let session = URLSession.shared
print("4")
session.dataTask(with: request) { data, response, error in
print("4.1")
guard error == nil else {
print("Error:", error ?? "")
return
}
print("4.2")
guard (response as? HTTPURLResponse)?
.statusCode == 200 else {
print("down")
return
}
print("4.3")
if let data = data {
if let dataString = String(decoding: data, as: UTF8.self).removeHtmlTags() {
if let startIndex = dataString.lastIndex(of: " ") {
let chars = dataString.distance(from: startIndex, to: dataString.endIndex)-1
ipAddress = String(dataString.suffix(chars))
}
}
print(ipAddress)
} else {
print("No data")
}
print("up - \(response!)")
}.resume()
print("Done.")
}
extension String {
// Credit - Andrew - https://stackoverflow.com/questions/25983558/stripping-out-html-tags-from-a-string
func removeHtmlTags() -> String? {
do {
guard let data = self.data(using: .utf8) else {
return nil
}
let attributed = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
return attributed.string
} catch {
return nil
}
}
}
Everything outside of the session prints, but nothing inside of it prints (4.x statements).
I deleted the AppSandbox because when I have AppSandbox as a Capability and turn on Outgoing Connections I get a crash with EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
But even with AppSandbox deleted it does not work.
The strange thing is this works fine in a playground (with a slight modification turning the String extension into a function within the playground), which really makes this a head scratcher for me.
Here's my playground code:
import AppKit
let userName = "yourUserName"
let password = "yourPassword"
let domain = "yourDomainName"
let ftp = "ftp"
let www = "www"
let checkIPURL = URL(string: "https://svc.joker.com/nic/checkip")
let domainUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(domain)")
let ftpUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(ftp).\(domain)")
let wwwUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(www).\(domain)")
var ipAddress = ""
if let url = checkIPURL {
print("1 - \(url)")
var request = URLRequest(url: url)
print("2 - \(request.url!)")
request.httpMethod = "POST"
print("3")
let session = URLSession.shared
print("4")
session.dataTask(with: request) { data, response, error in
print("4.1")
guard error == nil else {
print("Error:", error ?? "")
return
}
print("4.2")
guard (response as? HTTPURLResponse)?
.statusCode == 200 else {
print("down")
return
}
print("4.3")
if let data = data {
//if let dataString = String(decoding: data, as: UTF8.self).removeHtmlTags() {
if let dataString = removeHtmlTags(data: data) {
if let startIndex = dataString.lastIndex(of: " ") {
let chars = dataString.distance(from: startIndex, to: dataString.endIndex)-1
ipAddress = String(dataString.suffix(chars))
}
}
print(ipAddress)
} else {
print("No data")
}
print("up - \(response!)")
}.resume()
print("Done.")
}
func removeHtmlTags(data: Data) -> String? {
do {
let attributed = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
return attributed.string
} catch {
return nil
}
}
Is there something else I need to do to get this to work within the command line tool app I am trying to build?

Swift POST Request Method Not Allowed

I Use Laravel as backend and I have below route to verify the users
$router->post('SignIn','Api\V1\UserProfileController#SignIn');
I have tested this route many time using postman and its working fine, now i want to send post request from my app using below request
let url = URL(string: "http://192.168.xxx.xxx/BARI/public/Api/V1/Verify")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let param : [String : Any] = ["ph_number" : userDefaults.string(forKey: "ph_number")!, "code" : smsNumberTF.text!]
request.httpBody = try? JSONSerialization.data(withJSONObject: param, options: [])
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = TimeInterval(30)
configuration.timeoutIntervalForResource = TimeInterval(30)
let session = URLSession(configuration: configuration)
let task = session.dataTask(with: url) { (data, urlResponse, error) in
if(error != nil){
DispatchQueue.main.async {
self.progress.stopAnimating()
self.isLoading = false
// show connection error alert
print("connection error : \(error?.localizedDescription)")
}
}else{
let outputStr = String(data: data!, encoding: String.Encoding.utf8) as String?
print(outputStr)
DispatchQueue.main.async {
do {
self.progress.stopAnimating()
self.isLoading = false
let jsonData = try JSONDecoder().decode(BasicResponse.self, from: data!)
if(jsonData.statusCode == 1000){
// let userDefaults = UserDefaults.standard
// userDefaults.set("+964" + self.phoneET.text!, forKey: "contact_number")
// let vc = Verfiy()
// self.navigationController?.pushViewController(vc, animated: true)
}else{
//self.alert.show(target: self.view, message: jsonData.message!)
}
}
catch let jsonerr {
print("error serrializing error",jsonerr)
}
}
}
}
task.resume()
But Im getting Method Not Allowed response back? what Im missing her!?
Any Help will be much appreciated

How to put image to NSCache in Swift?

I make some code using swift 4 to load image from URL, but every time I add images to server, it took a lot of time to load it in colection view or table view. I want to try store it in NScache but i dont understand to do it. can anyone help me, I'm new in swift :(
#objc func loadPosts() {
let url = URL(string: "http://someURL/Url.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body = "phomepost=\(homepost)"
request.httpBody = body.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil {
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
self.comments.removeAll(keepingCapacity: false)
self.images.removeAll(keepingCapacity: false)
self.collectionView?.reloadData()
guard let parseJSON = json else {
print("Error While Parsing")
return
}
guard let posts = parseJSON["posts"] as? [AnyObject] else {
print("Error while parseJSONing")
return
}
self.comments = posts.reversed()
for i in 0 ..< self.comments.count {
let path = self.comments[i]["path"] as? String
if !path!.isEmpty {
let url = NSURL(string: path!)!
let imageData = try? Data(contentsOf: url as URL)
let image = UIImage(data: imageData! as Data)!
self.images.append(image)
} else {
let image = UIImage()
self.images.append(image)
}
}
self.collectionView?.reloadData()
//print(posts.count)
} catch {
print(error)
}
}else{
print(error)
}
})
}.resume()
}
You can use something like this:
private let cache = NSCache<NSString, NSData>()
.....
func downloadImage(url: String, handler: #escaping(Data?, Error?) -> Void){
let cacheID = NSString(string: url)
if let cachedData = cache.object(forKey: cacheID) {
handler((cachedData as Data), nil)
}else{
if let url = URL(string: url) {
let session = URLSession(configuration: urlSessionConfig)
var request = URLRequest(url: url)
request.cachePolicy = .returnCacheDataElseLoad
request.httpMethod = "get"
session.dataTask(with: request) { (data, response, error) in
if let _data = data {
self.cache.setObject(_data as NSData, forKey: cacheID)
handler(_data, nil)
}else{
handler(nil, error)
}
}.resume()
} else {
// NetworkError is a custom error
handler(nil, NetworkError.invalidURL)
}
}
}
}
This will add a small animation while loading using image set.
let imageCache = NSCache<AnyObject, AnyObject>()
extension UIImageView {
func loadImageFromUrl(urlString: String) {
let loader1 = UIImage(named: "loaderImage1.png")
let loader2 = UIImage(named: "loaderImage2.png")
let loader3 = UIImage(named: "loaderImage3.png")
let imageArray = [loader1, loader2, loader3]
let animatedImage = UIImage.animatedImage(with: imageArray as! [UIImage], duration: 1.7)
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage{
self.image = imageFromCache
return
} else {
self.image = animatedImage
Alamofire.request(urlString, method: .get).response { (responseData) in
if let data = responseData.data {
DispatchQueue.main.async {
if let imageToCache = UIImage(data: data){
imageCache.setObject(imageToCache, forKey: urlString as AnyObject)
self.image = imageToCache
}
}
}
} //alamofire
}
}
}

Checking Http Status Swift4

I'm a bit confused about credentials and HttpStatus.
I'm making a login page in Swift 4/XCode9, that connects to an api.
Here is what I do when the login button is tapped:
#IBAction func loginTapped(_ sender: Any) {
let loginString = String(format: "%#:%#", usernametext.text!, passwordtext.text!)
let loginData = loginString.data(using: String.Encoding.utf8)!
let base64LoginString = loginData.base64EncodedString()
var Base = base64LoginString
let url = URL(string: "SOME URL")!
var request = URLRequest(url: url)
request.addValue("Basic \(Base)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse {
print("status code = \(httpStatus.statusCode)")
}
}
task.resume()
view.endEditing(true)
}
Everything works fine but I don't know how to check the httpstatus.
If I get wrong credentials I want to stay on the login page and not perform segue to the next view.
Try this code
func checkStatusCode(response:URLResponse?) -> Bool {
guard let statusCode = (response as? HTTPURLResponse)?.statusCode else {
print("Invalid Response")
return false
}
if statusCode != 200 {
print("Invalid File")
return false
}
return true
}
Usage:
if (self.checkStatusCode(response: response)) {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "showW", sender: self)
}
} else {
//added an alert
}

Login Connection, method Get swift with API

I want to connect in an app in swift 2.1
I have a button logIn and I make a function loginButton.
I want to recover my url: localhost/connexion/login/password
And with that I want to say if the user is in the database it's ok !
But I don't really anderstant swift, I'm a beginner in this language.
So there is my code:
#IBAction func loginButton(sender: AnyObject) {
NSLog("login ok")
let _login = loginText.text
let _password = passwordText.text
if(_login!.isEmpty || _password!.isEmpty){
var alert:UIAlertView = UIAlertView()
alert.title = "Error"
alert.message = "Entrez vos identifiants"
alert.delegate = self
alert.addButtonWithTitle("OK")
alert.show()
} else{
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:8888/connexion/"+_login!+"/"+_password!)!)
request.HTTPMethod = "GET"
let postString = "login=\(_login!)&pass=\(_password)"
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request)
task.resume();
}
}
I have follow this before How to make an HTTP request in Swift?
but it doesn't work.
I tried a lot of things, but without really understand what happened and I don't find a great tutorial with very good explanation. If someone can explain me how to do it I will be very happy !
I think for sending data to server you should create a "POST" request and use NSURLSession API to send data
#IBAction func loginButton(sender: AnyObject) {
NSLog("login ok")
let _login = loginText.text
let _password = passwordText.text
if(_login.isEmpty || _password.isEmpty){
var alert:UIAlertView = UIAlertView()
alert.title = "Error"
alert.message = "Entrez vos identifiants"
alert.delegate = self
alert.addButtonWithTitle("OK")
alert.show()
} else{
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:8888/connexion/login")!)
request.HTTPMethod = "POST"
let params = ["login": _login, "pass": _password]
do {
let data = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
request.HTTPBody = data
} catch let error as NSError {
print("json error: \(error.localizedDescription)")
}
let loginTask = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
guard let data = data, let _ = response where error == nil else {
print("error")
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
print(json)
} catch let error as NSError {
print("json error: \(error.localizedDescription)")
}
})
loginTask.resume()
}
}
for using "GET" replace else part with
let url = "http://localhost:8888/connexion/login=\(_login)&pass=\(_password)"
let urlString = url.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let request = NSURLRequest(URL: NSURL(string: urlString)!)
let loginTask = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
guard let data = data, let _ = response where error == nil else {
print("error")
return
}
/*do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
print(json)
} catch let error as NSError {
print("json error: \(error.localizedDescription)")
}*/
if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data!, encoding:NSUTF8StringEncoding)
print("responseString = \(responseString)")
})
loginTask.resume()