Alamofire Swift get html source - html

I just want to retrieve the html source from a simple website.
#IBAction func scan_func(sender: AnyObject) {
Alamofire.request(.GET, "http://www.example.com")
.response { request, response, data, error in
print(request)
print(response)
print(data)
}
}
I already have successfully added "App Transport Security Settings" and "Allow Arbitrary Loads" to info.plist to load http content.
When I run that code I only get an output like this:
XCODE - hexadecimal output
I hope you can help me.
kind regards

You are printing out the raw bytes of the data. I'm guessing you are looking for a way to print out the corresponding string representation.
You could for instance do this with Alamofire's provided closure:
Alamofire.request(.GET, "http://www.example.com")
.responseString { response in
print("Response String: \(response.result.value)")
}
(Check out the documentation here)
Alternatively, you could convert the string yourself:
Alamofire.request(.GET, "http://www.example.com")
.response { request, response, data, error in
print(String(data: data, encoding: String.Encoding.utf8))
}
Apple String reference documentation

Related

Could not cast value of type '__NSDictionaryI'

I m using this code to call my rest web service.
But if I try to decode the result of web service call I received error.
class func callPostServiceReturnJson(apiUrl urlString: String, parameters params : [String: AnyObject]?, parentViewController parentVC: UIViewController, successBlock success : #escaping ( _ responseData : AnyObject, _ message: String) -> Void, failureBlock failure: #escaping (_ error: Error) -> Void) {
if Utility.checkNetworkConnectivityWithDisplayAlert(isShowAlert: true) {
var strMainUrl:String! = urlString + "?"
for dicd in params! {
strMainUrl.append("\(dicd.key)=\(dicd.value)&")
}
print("Print Rest API : \(strMainUrl ?? "")")
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 120
manager.request(urlString, method: .get, parameters: params)
.responseJSON {
response in
switch (response.result) {
case .success:
do{
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)
}catch{
print("errore durante la decodifica dei dati: \(error)")
}
if((response.result.value) != nil) {
success(response as AnyObject, "Successfull")
}
break
case .failure(let error):
print(error)
if error._code == NSURLErrorTimedOut {
//HANDLE TIMEOUT HERE
print(error.localizedDescription)
failure(error)
} else {
print("\n\nAuth request failed with error:\n \(error)")
failure(error)
}
break
}
}
} else {
parentVC.hideProgressBar();
Utility.showAlertMessage(withTitle: EMPTY_STRING, message: NETWORK_ERROR_MSG, delegate: nil, parentViewController: parentVC)
}
}
This is the error that I can print:
Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
2021-09-27 16:34:49.810245+0200 ArrivaArrivaStore[15017:380373] Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
CoreSimulator 732.18.6 - Device: iPhone 8 (6F09ED5B-8607-4E47-8E2E-A89243B9BA90) - Runtime: iOS 14.4 (18D46) - DeviceType: iPhone 8
I generated OrderStore.swift class from https://app.quicktype.io/
//EDIT
.responseJSON returns deserialized JSON, in this case a Dictionary. It cannot be cast to Data what the error clearly confirms.
To get the raw data you have to specify .responseData
Replace
.responseJSON {
response in
switch (response.result) {
case .success:
do {
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)
with
.responseData {
response in
switch response.result {
case .success(let data):
do {
let users = try JSONDecoder().decode(OrderStore.self, from: data)
Consider that AF 5 supports even .responseDecodable to decode directly into the model
.responseDecodable {
(response : DataResponse<OrderStore,AFError>) in
switch response.result {
case .success(let users): print(users)
Side notes:
As mentioned in your previous question there is no AnyObject in the AF API. The parameters are [String:Any] and responseData is the decoded type. I recommend to make the function generic and use the convenient Result type.
Delete the break statements. This is Swift.
This is an addendum to Vadian's answer. I'm trying to illustrate the process that lead you into this error, with the hopes that you can notice it in the future, before it leads you astray
This is a pretty common "pattern" of error.
Picture it as though you're traversing a maze, starting from some initial data format, and trying to get to some destination data format. At each point along the way, there are several options to choose from, some which get you closer to your goal, and some which lead you further away.
You've chosen to enter the maze at the entryway called responseJSON, whose callback will give you a AFDownloadResponse<Any> (which is the inferred type of the variable you called response).
JSON structures always have an array or dictionary at the top level. Since Alamofire can't statically know which kind of JSON you'll be dealing with, it models this with an Any. At runtime, the type of the Value will be either NSDictionary (or one of its concrete subclasses, like __NSDictionaryI) or NSArray (or one of its concrete subclasses).
You then decide to get the result of that response. Its static type is Result<Any, Error>. You switch over this error, ensuring you're dealing with the success case and not the failure case. Inexplicably, you ignore the payload value associated with the success, but later force unwrap it out with result.response.value!.
result.response.value is an Any, but to placate the compiler your force-cast it to a Data. But we already know this will only ever be an NSArray or NSDictionary, so this will never work.
You could keep wandering around in this area of the maze, and stumble to the end goal via a long path. For example, you could force cast to NSDictionary, then re-serialize that dictionary structure back to a JSON string, which you can turn into Data, only for you to then pass it to JSONDecoder().decode, which will then decode that JSON back. Of course, this is all awfully round-about and wasteful. The issue was the that responseJSON maze entrance was not the right one for where you're trying to go!
You could have instead entered into the responseData maze entrance, which gets you right to your Data destination!
Though you might then realize that the Data was a red herring all along. You didn't actually want Data. You wanted to decode an OrderStore, and Data was how you thought you needed to get there. But it turns out that so many people were entering through the Data entrance with the intent to decode some JSON, that the Alamofire people carved out a new entrance just for you: responseDecodable. It takes you right to the OrderStore, and fiddles around with the JSON, Data or whatever, under the hood where you don't have to worry about it.

How to detect when Alamofire request is null?

I am using Alamofire to do my requests of my API on my Swift application and it works well but I also want to detect when the JSON response is equals to null.
I have tried comparing the response to nil and NSNull but none of those worked for me. I also have tried using JSON.empty but it also does not seem to work. Further, I have created a default option on my switch application trying to catch the options that are not success or failure.
Actually I have only maintained the JSON.empty option but it never enters on else statement.
This is the code that I have right now:
Alamofire.request(encodedUrl!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
switch(response.result) {
case .success(_):
if let JSON = response.result.value as? [[String : AnyObject]]{
if JSON.isEmpty == false{
//Here the code if the request returns data
}else{
//Here I wanted to use the code if null is retrieved
}
}else{
//The JSON cannot be converted
}
break
case .failure(_):
//Failure
break
}
}
How can I handle null responses on Alamofire?
Thanks in advance!
According to you code, it'll hit the // The JSON cannot be converted since null can't be casted to [[String: AnyObject]].

How to debug network request Swift

I'm making a http request to an API with JSON in the body of the request. I know for a fact that my Dictionary<String, String> containing the JSON data is correct, still I'm getting a response from the server that my input data is not valid. I'm doing something very similar to this: Swift 2.0 url post request. I even tried the extension suggested there but without success.
how should I debug this? I can't find any way to print my whole request to the console. I want to know what my URLRequest actually contains just before I send the request. Also, I want to know that this hex gibberish is actually the right gibberish I meant it to be, how should I do this?
Nothing special about that? Just write an extension and print whatever you want
example:
extension Data {
func toString() -> String? {
return String(data: self, encoding: .utf8)
}
}
extension URLRequest {
func log() {
print("\(httpMethod ?? "") \(self)")
print("BODY \n \(httpBody?.toString())")
print("HEADERS \n \(allHTTPHeaderFields)")
}
}
Usage:
request.log()
Sample log:
POST https://httpbin.org/
BODY
Optional("password=xxx&username=xxx")
HEADERS
Optional(["Content-Type": "application/x-www-form-urlencoded; charset=utf-8"])

Swift 2.0 How to parse JSON?

I am coding a hangman game and am loading the possible words into my app using json text files. I tried to follow the examples of others on this website but I am getting errors from Xcode.
I tried the following code based on another answer:
import Foundation
var error: NSError?
let jsonData: NSData = /* get your json data */
let jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as NSDictionary
But I got an errors on line 4 with jsonDict that said "call can throw but is not marked with try, and the error is not handled" and "Type JSONReadingOptions does not conform to protocol NilLiteralConvertible".
Here is the JSON File I would like to parse:
{
“wordList” : {
“difficulty” : “Easy”
“list” : [
“fireplace”,
“apple”,
“january”,
“tooth”,
“cookies”,
“mysterious”,
“essential”,
“magenta",
“darling”,
“pterodactyl”
]}}
I would like to be able to go into my list array and get values. Thank you very much for any help!
In Swift 2 you need to use the new error handling API instead of passing a reference to an NSError:
do {
let jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions(rawValue: 0)) as? NSDictionary
if let jsonDict = jsonDict {
// work with dictionary here
} else {
// more error handling
}
} catch let error as NSError {
// error handling
}
You also can't pass nil as value to the options parameter, you need to pass a value of type NSJSONReadingOptions.
That said, the most common approach for parsing JSON in Swift is currently using third party libraries, such as Argo because they can save you a lot of code that is necessary to validate and safely cast the content of your JSON data to the correct Swift types.

How do I access the data when I am using NSURLSession?

I am new to iOS development. I am using Swift and I have very little experience with Objective-C, so some of the other possibly related answers are tricky to understand. I am trying to understand how to use NSURLSession to get some data from a JSON file on the Web. I found some useful information about getting a file from a URL, but like this other StackOverflow user (NSURLSessionDataTask dataTaskWithURL completion handler not getting called), I heard that NSURLConnection was not the current way to get data, so I'm trying to use NSURLSession.
When I am getting my JSON from the bundle, I am using this extension to
Dictionary (I am pretty sure I got this code from a tutorial):
static func loadJSONFromBundle(filename: String) -> Dictionary<String, AnyObject>? {
let path = NSBundle.mainBundle().pathForResource(filename, ofType: ".json")
if !path {
println("Could not find level file: \(filename)")
return nil
}
var error: NSError?
let data: NSData? = NSData(contentsOfFile: path, options: NSDataReadingOptions(),
error: &error)
if !data {
println("Could not load level file: \(filename), error: \(error!)")
return nil
}
let dictionary: AnyObject! = NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions(), error: &error)
if !dictionary {
println("Level file '\(filename)' is not valid JSON: \(error!)")
return nil
}
return dictionary as? Dictionary<String, AnyObject>
}
I'd like to do something similar for getting a dictionary from a JSON file that is on the web because I don't anticipate wanting to include all of my JSON files in the bundle. So far, I have this:
static func loadJSONFromWeb(urlstring: String) -> Dictionary<String, AnyObject>? {
let url = NSURL(string: urlstring)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: NSOperationQueue())
var error: NSError?
//I think I am using the completionHandler incorrectly. I'd like to access the data from the download
let task = session.downloadTaskWithRequest(NSURLRequest(URL: url), {(url, response, error) in println("The response is: \(response)")
})
task.resume()
//Isn't this contentsOfURL thing supposed to go with the connection stuff rather than the session stuff?
//How can I do this with a session? How can I create and use a completionHandler? This way seems clunky.
let data: NSData? = NSData(contentsOfURL: url)
if !data {
println("Could not load data from file: \(url), error: \(error!)")
return nil
}
println("The data is: \(data)")
let dictionary: AnyObject! = NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions(), error: &error)
if !dictionary {
println("The file at '\(url)' is not valid JSON, error: \(error!)")
return nil
}
return dictionary as? Dictionary<String, AnyObject>
}
I think that my actual question that most needs answering is this: Where
is the data? I don't think I am using sessions and tasks correctly. I feel like I'm
starting a session to connect to a specific URL and using resume() to
start the download task I want to make happen, but I don't know how to
get the data from that JSON file.
If I need to use a completionHandler and a request in a way similar to what I found here:
(popViewControllerAnimated work slow inside NSURLSessionDataTask) can someone please explain how the 'data' in the completionHandler relates to the data in the fie I am trying to read/download? I am a bit baffled by the completionHandler and how to use it properly.
I looked at the documentation for NSData as well, but I didn't see anything that helped me understand how to get data from my session (or how to initialize an instance of NSData given my session). As far as I can tell form the documentation for NSURLDownloadTask, the task itself is not how I can access the data. It looks like the data comes from the session and task through the completionHandler.
EDIT:
I also looked at the documentation for NSURLSessionDownloadDelegate, but I could really use an example in Swift with some explanation about how to use the delegate. This led me to the URL Loading System Programming Guide. I'm guessing the benefits of using a session must be huge if the documentation is this complicated. I'm going to keep looking for more information on the URL Loading System.
I found this answer helpful (but I'm so new I can't upvote anything yet): https://stackoverflow.com/a/22177659/3842582 It helped me see that I am probably going to need to learn to use a delegate.
I also looked at the URL Loading System Programming Guide. I think what I really need is help with a completionHandler. How can I get my data? Or, am I already doing it correctly using NSData(contentsOfURL: url) (because I don't think I am).
Thank you in advance for any help you can offer!
First, let data: NSData? = NSData(contentsOfURL: url) will return your JSON synchronously. Did you try that and get this working simply? That way you can get started with the rest of your processing while figuring out NSURLSession.
If you're going to use NSURLSession, or a lot of other things in iOS, you need to learn delegates. Fortunately, they're easy. In terms of syntax you just add it to your class declaration like you were inheriting from it. What that does is say that you are going to implement at least the required functions for the delegate. These are callback functions which are generally pretty well documented. It is quite straightforward once you understand it.
If this is not a "heavyweight" project that really needs NSURLSession, you should look at this Swift library. Besides being a really nice way to deal with JSON there is a synchronous call to directly load the JSON from a url. https://github.com/dankogai/swift-json/
Why is NSURLConnection not the correct way to get data? You just should be careful with synchronous requests. Here is an example of how to get data from an url.
func synchronousExampleRequest() -> NSDictionary {
//creating the request
let url: NSURL! = NSURL(string: "http://exampledomain/apiexample.json")
var request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
var error: NSError?
var response: NSURLResponse?
let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
error = nil
let resultDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
return resultDictionary
}