I am using Alamofire for my requests and I get cookies in some of them, everything works fine when I launch the app and use it but when I kill the app and reopen the cookies are not there anymore. I searched a lot and found this but none of the answers helped.
I try to save the cookies after each request and load them before sending request as below:
func saveCookies(response: DataResponse<Any>) {
let headerFields = response.response?.allHeaderFields as! [String: String]
let url = response.response?.url
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url!)
var cookieArray = [[HTTPCookiePropertyKey: Any]]()
for cookie in cookies {
cookieArray.append(cookie.properties!)
}
UserDefaults.standard.set(cookieArray, forKey: "savedCookies")
UserDefaults.standard.synchronize()
}
func loadCookies() {
guard let cookieArray = UserDefaults.standard.array(forKey: "savedCookies") as? [[HTTPCookiePropertyKey: Any]] else { return }
for cookieProperties in cookieArray {
if let cookie = HTTPCookie(properties: cookieProperties) {
HTTPCookieStorage.shared.setCookie(cookie)
}
}
}
But still when I kill the app, I can't get the data.
Try to save your cookies in UserDefaults like this:
var authToken: String {
get {
return defaults.value(forKey: TOKEN_KEY) as! String
}
set {
defaults.set(newValue, forKey: TOKEN_KEY)
}
}
Related
I made app which login in SFSafariViewController. It works well when login. but after I logout if I try to login it again, I'm already logged in. This is because my automatic login information is stored in SFSafariViewController. I tried to delete cache and cookies but it doesn't work. :(
this is my login code.
func requestCode() {
let scope = "user"
let urlString = "https://github.com/login/oauth/authorize?client_id=\(clientId)&scope=\(scope)"
guard let url = URL(string: urlString) else {
return
}
URLCache.shared.removeAllCachedResponses()
if let cookies = HTTPCookieStorage.shared.cookies {
for cookie in cookies {
HTTPCookieStorage.shared.deleteCookie(cookie)
}
}
let safariViewController = SFSafariViewController(url: url)
safariViewController.delegate = self
safariViewController.modalPresentationStyle = .automatic
if let topViewController = UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).flatMap({ $0.windows }).first(where: { $0.isKeyWindow }) {
topViewController.rootViewController?.present(safariViewController, animated: true, completion: nil)
}
}
prefersEphemeralWebBrowserSession = true
it makes your browser to private mode!!!
so you don't need to logout.
I'm testing Alamofire with ssl certificate.
using swift and swiftUI I wrote this 2 functions to load the ssl from a bundle and make the request using Alamofire.
func getCertificate() -> [SecCertificate] {
let url = Bundle.main.url(forResource: "ssl", withExtension: "cer")
let localCer = try! Data(contentsOf: url!) as CFData
guard let certificate = SecCertificateCreateWithData(nil, localCer) else {
return []
}
return [certificate]
}
func loginUserIcrew(userName: String, password: String){
let evaluators: [String: ServerTrustEvaluating] = [
linkIcrew: PinnedCertificatesTrustEvaluator(certificates:getCertificate())
]
let manager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: manager)
session.request (linkIcrew,method: .get, encoding: URLEncoding.default)
.response { response in
print(response)
}
}
and I using it in a simple button like this
struct SalaryStart: View {
#ObservedObject var ss = SalaryManager()
var body: some View {
Button {
ss.loginUserIcrew(userName: "user", password: "pass")
} label: {
Text("test")
}
}
}
I'm getting the error : Alamofire.AFError.sessionDeinitialized
any help how to solve tis issue? reading online looks like the session need to keep alive, but I don't understand what does it mean??
thanks for the help
sessionDeinitialized means what it says: your Session was deinitialized while the request was in progress and so it was cancelled. You need to keep the Session alive at least long enough to complete the request. Usually you want to use a single Session for all of your requests, so I suggest keeping it as a singleton.
I have a function that connects to an API to retrieve data. The API takes two parameters accessCode (provided by user in a text box) and then UDID (UDID of their device). I can parse the data from within the function, but only locally. I need to store the values that are returned but am unsure on how to return them properly. Essentially I need this to return the json object as a dictionary (I think...) so it can be parsed outside of the async task. I've read through the swift documentation and that's where I found out how to do the requests, but I can't find a way to store the returned values in memory for access outside of the function.
func getResponse(accessCode:String, UDID:String, _ completion: #escaping (NSDictionary) -> ()) {
let urlPath = "https://apihosthere.com/api/validate?accessCode=" + accessCode + "&UDID=" + UDID
guard let url = URL(string: urlPath) else { return }
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary {
let results = jsonResult as? NSDictionary
print(results)
completion(results!)
}
} catch {
//Catch Error here...
}
}
task.resume()
}
First of all don't use NSDictionary in Swift, use native [String:Any] and declare the type as optional to return nil if an error occurs.
And never use .mutableContainers in Swift, the option is useless.
func getResponse(accessCode:String, UDID:String, completion: #escaping ([String:Any]?) -> Void)) {
let urlPath = "https://apihosthere.com/api/validate?accessCode=" + accessCode + "&UDID=" + UDID
guard let url = URL(string: urlPath) else { return }
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error else {
print(error)
completion(nil)
return
}
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data!) as? [String:Any] {
print(jsonResult)
completion(jsonResult)
} else {
completion(nil)
}
} catch {
print(error)
completion(nil)
}
}
task.resume()
}
Your mistake is that you don't consider the closure, you have to execute the entire code inside the completion handler
#IBAction func StartWizard(_ sender: UIButton) {
//Store entered access code
let accessCode = AccessCodeField.text!
//Call API to validate Access Code
getResponse(accessCode:accessCode, UDID:myDeviceUDID) { [weak self] result in
if let accessCodeFound = result?["Found"] as? Bool {
print("Value of Found during function:")
//If access code is valid, go to License view
print(accessCodeFound)
if accessCodeFound {
//Load License View
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let licenseController = storyboard.instantiateViewController(identifier: "LicenseViewPanel")
self?.show(licenseController, sender: self)
}
}
}
}
}
Your completion closure should handle the obtained data. You would call the function like this:
getResponse(accessCode: "code", UDID: "udid", completion: { result in
// Do whatever you need to do with the dictionary result
}
Also, I'd recommend you to change your NSDictionary with a swift Dictionary.
This is what the API returns as a response
{
AccessCode = 00000000;
Client = "0000 - My Company Name";
EmailAddress = "brandon#brandonthomas.me";
FirstName = Brandon;
Found = 1;
LastName = Thomas;
Status = A;
UDIDregistered = 1;
}
And this is what calls the function. I am calling at after clicking a button after an access code is being entered in a text field.
#IBAction func StartWizard(_ sender: UIButton) {
//Store entered access code
let accessCode = AccessCodeField.text!
var accessCodeFound: Bool? = nil
//Call API to validate Access Code
getResponse(accessCode:accessCode, UDID:myDeviceUDID) { result in
accessCodeFound = result["Found"] as! Bool
print("Value of Found during function:")
print(accessCodeFound)
//accessCodeFound = true
}
//If access code is valid, go to License view
print("Value of Found after function:")
print(accessCodeFound)
//accessCodeFound = nil ???
//it seems the value is getting reset after the function completes
if accessCodeFound == true{
//Load License View
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let licenseController = storyboard.instantiateViewController(identifier: "LicenseViewPanel")
self.show(licenseController, sender: Any?.self)
}
}
First of all I want to say, I didn't find anyting about it on this site.
I want to save NSURL into NSUserDefaults to prevent loading image on every app open or the view open. I tried to achieve it like this but for some reason I can't. At least I think thats what should do it:
let productImageref = productsValue[indexPath.row]["Products"] as? String
cell.snusProductImageView.image = nil
if let url = self.productsValue[indexPath.row]["imageUrl"] as? NSURL {
cell.snusProductImageView.kf_showIndicatorWhenLoading = true
var storedUrl = defaults.objectForKey("imageUrl") as? NSURL
cell.snusProductImageView.kf_setImageWithURL(storedUrl)
}
else {
FIRStorage.storage().reference().child("\(productImageref!).png").downloadURLWithCompletion({(url, error)in
if error != nil{
print(error)
return
}else{
self.productsValue[indexPath.row]["imageUrl"] = url
self.defaults.setURL(url, forKey: "imageUrl")
self.productstable.reloadData()
dispatch_async(dispatch_get_main_queue(), {
})
}
})
}
If I am wrong then please correct me. Should saving the url-s into userdefaults do the trick?
What exactly I am doing wrong here? Maybe it is better to save it into CoreData but I thought that it would be overkill.
Why the KingFisher or SDWebImages library is not caching it?
Two things that might help: use synchronize after saving something to defaults and use URLForKey to get it back.
(And check that the thing you're saving really is a NSURL.)
Here's sample code that works in a project; compare it to yours (NSUserDefaults is broken for playgrounds.):
let defaults = NSUserDefaults.standardUserDefaults()
if let components = NSURLComponents(string: "http://localhost/"),
url = components.URL {
defaults.setURL(url, forKey: "imageUrl")
defaults.synchronize()
if let fetchedURL = defaults.URLForKey("imageUrl") {
print("\(fetchedURL) returned")
} else {
print("No URL in defaults")
}
} else {
print("Bad components")
}
print(defaults.dictionaryRepresentation())
You have to store URL like below:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setURL(yourURL:NSURL?, forKey: "imageURL")
And read NSUserDefaults like this:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.URLForKey("imageURL")
Hope this helps.
As i understood, you want to save multiple images url in NSUserDefaults
let url = NSURL(string: "http://localhost/")
var array = [NSString]()
array.append((url?.absoluteString)!)
NSUserDefaults.standardUserDefaults().setValue(array, forKey: "image")
NSUserDefaults.standardUserDefaults().synchronize()
if let fetchedURL = NSUserDefaults.standardUserDefaults().valueForKey("image") as! [String]? {
print("\(fetchedURL[0]) returned")
let fileUrl = NSURL(string: fetchedURL[0])
print(fileUrl)
} else {
print("No URL in defaults")
}
print results
http://localhost/ returned
Optional(http://localhost/)
I'm loading json data from webservice using Alamofire, one of my request return a json like this:
"lorem ipsum...",
"http://site.ed/image.jpg"
Then I create a var texto: [String] = [] to receive all texts.
Now I need to adapt to receive image to show in UITableView
What I already do:
func loadPosts() {
let url = "http://site.ed"
Alamofire.request(.GET, url)
.responseJSON { response in
if let value: AnyObject = response.result.value {
let post = JSON(value)
for (_, subJson) in post {
if(self.verifyUrl(subJson.stringValue)){
print("Valide URL \(subJson.stringValue)")
}
self.texto.append(subJson.stringValue)
}
}
}
}
func verifyUrl (urlString: String?) -> Bool {
if let urlString = urlString {
if let url = NSURL(string: urlString) {
return UIApplication.sharedApplication().canOpenURL(url)
}
}
return false
}
In this print("Valide URL") i need to get the real image and put into a table, how can i do that ?
Why not try some image library like KingFisher
What you need to do is just set imageView with url
imageView.kf_setImageWithURL(NSURL(string: "http://your_image_url.png")!)