I am retrieving data from URL like this:
let url = NSURL(string: baseURL)
let request = NSURLRequest(URL: url!)
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error == nil {
let swiftyJSON = JSON(data: data!)
let results = swiftyJSON[0]["name"]
print(results)
} else {
print("error")
}
}
For the above, I get data like this:
[
{
"_id":"123",
"_rev":"345",
"name":"hey"
},
{
"_id":"133",
"_rev":"33345",
"name":"hello"
}
]
I always end up in error block and I am not sure why?
I pasted the JSON in chrome console and able to do swiftyJSON[0].name. I would like to print all elements from the above json OBJECT.
Error:
error Optional(Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x7f87514ab570 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=8, _kCFStreamErrorDomainKey=12}}, NSErrorFailingURLStringKey=http://localhost:3000/idea, NSErrorFailingURLKey=http://localhost:3000/idea, _kCFStreamErrorDomainKey=12, _kCFStreamErrorCodeKey=8, NSLocalizedDescription=A server with the specified hostname could not be found.})
Please note, localhost:3000 is on.
The error you pasted may be the request's hostname not found.
"A server with the specified hostname could not be found." The JSON parse seems right totally.
The error is not in the JSON data. The data cannot be retrieved in the first place since the URL http://localhost:3000/idea is not working.
Most likey, the URL is valid on your Mac but not on your iPhone. The URL would only be valid if your server side was running on the iPhone or simulator itself, which is rather unlikely.
localhost isn't a global address. On your Mac, it refers to your Mac. On an iPhone, it refers to the iPhone itself.
Open the Network Utility app on your Mac, look up the IP address and replace localhost with your IP address, e.g. http://192.168.1.37:3000/idea. Then your iOS app will be able to retrieve the data.
Related
I am trying to send a very simple dictionary to the json file in my local host using swift (Alamofire)
Here is what I've done :
let parameters: Parameters = ["name" : "Danial"]
Alamofire.request("http://localhost/testing.json", method: HTTPMethod.post, parameters: parameters).response { result in
if result.response?.statusCode != nil {
if let status = (result.response?.statusCode)! as? Int {
print("status : \(status)")
}
}
}
and inside my testing.json I have the following :
{
"x":"y"
}
and I get the the http status 412 (frequently) and the 200 (without in apperance of the new json in the json file) rarely . I am very new to this networking stuff . thus , please dont attack my question as if I must know this simple thing . This has already taken me 2 days to resolve yet i am here :|
by the way there should be no error in connection as my get protocol seems to be working fine
OK, here are a couple of things I see.
When you send a POST to a server, the URL must be to a Web Service or a web app of some kind. Here it appears you are trying to POST to a resource file. Static resource files will not update automatically.
You didn't specify the encoding, so you didn't post JSON (application/json), you posted Form URL Encoded (application/x-www-form-urlencoded). Instead of being { "name": "Danial" }, you sent name=Danial.
You need to set the encoding to JSON.
let parameters: Parameters = ["name" : "Danial"]
Alamofire.request("http://localhost/testing.json",
method: HTTPMethod.post,
parameters: parameters,
encoding: JSONEncoding.default).response { result in
if result.response?.statusCode != nil {
if let status = (result.response?.statusCode)! as? Int {
print("status : \(status)")
}
}
}
Important Fact
I forgot to mention an important factor in the question. I am running this in a TestCase. I think this issue has something to do with the TestCase not awaiting for async completionHandler to return
Migrated out from Alamofire to SwiftHTTP, since I found this much easier.
On SwiftHHTP there is no way to know what URL got generated, what error it returned. For example, I tried to see the opt.debugDescription variable, it returned something cryptic like description String "<SwiftHTTP.HTTP: 0x60000007e540>"
Steps I have followed
I have set YES to Allow Arbitrary Loads.
Safari on the iPhone Simulator responds with the correct JSON if I paste fullurl ->http://120.0.0.1:8080/myapi/Driver/getDriver?driver=2243&domain=4345&key=asdfasdf. Even catalina.out on the tomcat server running on my mac responds with a debug message.
But when I run this in a test case under Xcode the below code prints none of debug print's.
--1->, --2-->, --3-->, nothing got printed.
Debugger breakpoints also dont stop here.
CODE
var getData = [String:String]()
getData = ["domain": "4345",
"driver" : "2343",
"key" : "asdfasdf"]
var urlComponents = URLComponents(string: fullURL)!
var queryItems = [URLQueryItem]()
queryItems = self.getData.map{ URLQueryItem(name : $0.0, value : $0.1) }
urlComponents.queryItems = queryItems
print("fullurl ->"+(urlComponents.url)!.absoluteString)
do {
let opt = try HTTP.GET((urlComponents.url)!.absoluteString)
opt.start { response in
if let err = response.error {
print("--1-> error: \(err.localizedDescription)")
return //also notify app of failure as needed
}
print("--2--> opt finished: \(response.description)")
self.responseData = response
}
} catch let error {
print("--3--> got an error creating the request: \(error)")
}
EDIT
Even after changing the code to https or http://www.google.com, same result.
let testComponents = URLComponents(string: "https://www.google.com")!
URLSession.shared.dataTask(with: (testComponents.url)!, completionHandler: {
(data, response, error) in
if(error != nil){
print("..1>..")
}else{
do{
print ("..2>.." )
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
self.responseData = json
}catch let error as NSError{
print("..3>..")
}
}
}).resume()
EDIT 1
Tried from here #Vivek's answer.
callWebService(url: (urlComponents.url)!.absoluteString)
.
.
func callWebService(url : String) {
.
.
let callURL = URL.init(string: url)
Nothing got printed again, Error / JSON, nothing.
Yes, Unit Tests don't wait by default for the completionHandler to be called. If you call asynchronous functions in tests, you don't need to change the function's code, but the behavior of the test.
The solution: XCTestExpectation
In your test-class (the subclass of XCTest), add this property:
var expectation: XCTestExpectation?
A test-function for an asynchronous request could basically look like this:
func testRequest() {
expectation = expectation(description: "Fetched sites") //1
//2
some.asyncStuffWithCompletionHandler() {
someData in
if someData == nil {
XCTestFail("no data") //3
return
}
//looks like the request was successful
expectation?.fulfill() //4
}
//5
waitForExpectations(timeout: 30, handler: nil)
}
Explanation
This defines, what you expect the tested code to do. But actually, it's not important, what you add as description. It's just an information for you, when running the test
This is the function with a completionHandler, you are calling
If you want to let the test fail within the completionHanlder, call XCTestFail()
If everything in the completionHandler worked as expected, fulfill the expectation by calling expectation?.fulfill.
Here comes the important part: This part of the code will be executed before the completionHandler! If this would be the end of the function, the test would be stopped. That's why we tell the test to wait until the expectations are fulfilled (or a certain amount of time passed)
There is an interesting blog post about Unit Tests. (see the section "XCTestExpectation") It's written in an old Swift syntax, but the concept is the same.
I've been trying to retreive my json data for my iOS App. I tried many different sollutions but none of these worked properly for me. So this was the code I was using to read the json from the url and convert it.
let url = NSURL(string: "http://www.blind3d.byethost7.com/service.php")!
func load() {
do {
let request = NSURLRequest(URL: url)
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
self.handleData(data)
}
catch let error as NSError {
print("wieso dont you do siss : \(NSURLRequest(URL: url))")
self.handleError(error)
}
}
func handleError(error : NSError?) {
print("wieso dont you do siss : \(NSURLRequest(URL: url))")
NSLog("%#", "Error with loading from \(url): \(error)")
}
func handleData(data : NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
handleJSON(json)
}
catch let error as NSError {
handleError(error)
}
}
but somehow this isn't running properly. I am always getting this error when I am executing this method: NSJSONSerialization
Error with loading from http://www.blind3d.byethost7.com/service.php: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})
The json data I wanted to use for my app is here
Thank you for your help guys
The problem occurs because there it no actual JSON in the data variable. I tried your web service, and this is what you get returned in the data, along with all the other error html tags:
"This site requires Javascript to work, please enable Javascript in your
browser or use a browser with Javascript support"
The full response:
<html><body><script type="text/javascript" src="/aes.js" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("f655ba9d09a112d4968c63579db590b4"),b=toNumbers("98344c2eee86c3994890592585b49f80"),c=toNumbers("26049265c821fd7227c09955cbb61ebc");document.cookie="__test="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";location.href="http://www.blind3d.byethost7.com/service.php?ckattempt=1";</script><noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript></body></html>
This seems to happen, because there is some Javascript injected in the webpage you are trying to parse from, probably for statistics, or some other unknown reasons.
For checking by yourself, print your data - print(data), before calling self.handleData(data)
Try removing \r\n or escape them with '\' like
\\r\\n
and you are good to go. BTW, using json is painful in swift like this, SwiftyJSON is a necessary library if you deal with json frequently.
This is the result of installed "testCookie-nginx-module"
It's supposed to prevent DDOS attacks on your hosting
When you visit your site for the first time, it sends you this JS code, which your browser is supposed to process and set a special cookie (its name it _test)
Only with this cookie attached to your IP your browser can see the original content (your content: html php json etc.)
Seems the only way for you - is to process this JS (with AES, HEX and other JS functions, get the right _test cookie and send another request with this cookie)
I have been trying to connect my ios application to my restful web API through http basic authentication but I am unable to connect. Here is my code:
let URL = NSURL(string:"https://devWebsvc1.whateverYolo.local:11201/api/webcall")
let theRequest = NSMutableURLRequest(URL:URL)
let session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration())
theRequest.HTTPMethod = "POST"
theRequest.addValue("application/json", forHTTPHeaderField:"Content-Type")
theRequest.addValue("application/json", forHTTPHeaderField:"Accept")
let credential = NSURLCredential(user:"username", password:"password", persistence: NSURLCredentialPersistence.ForSession)
let protectionSpace = NSURLProtectionSpace(Host: URL?.host)!, port:11201, 'protocol': URL?.scheme, realm: nil, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
let credentialStorage = NSURLCredentialStorage.sharedCredentialStorage()
credentialStorage.setDefaultCredential(credential,forProtectionSpace:protectionSpace)
theSession.configuration.URLCredentialsStorage = credentialStorage
let task = theSession.dataTaskWithRequest(theRequest, completionHandler : {data, response, error -> Void in
if error != nil
{print("\(error)")}})
Error message is :-
Optional(Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey={type = immutable, count = 1, values = (
0 :
)}, NSUnderlyingError=0x7fe023520170 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates={type = immutable, count = 1, values = (
0 :
)}}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://devwebsvc1.whateverYolo.local:11201/api/Device, NSErrorFailingURLStringKey=https://devwebsvc1.whateverYolo.local:11201/api/Device, NSErrorClientCertificateStateKey=0})
Do you guys know what could be the error? Any help is appreciated. I am using xcode 7 by the way.
Error may be in this line :-
theRequest.addValue("application/json", forHTTPHeaderField:"Accept")
You should go to this google extension and find what's the value for the Field "Accept"
chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo/RestClient.html
add Your url ,username and password and click submit and find all of your Header Field are correct like this, Check the value for Content-Type also
I have an app (the same one from my previous post about unwrapping nil. I really hate nil now.) that searches the iTunes store and returns data in JSON. I have it working, it gets the song name, artist name, everything! I created an #IBAction button for playing the song's preview. The JSON has a property that is the url to the song preview. When I click the button, it does the following:
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(url, ofType: "m4a")!)
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
The url is this: http://a1993.phobos.apple.com/us/r1000/101/Music/b7/b3/e0/mzm.ooahqslp.aac.p.m4a. I know my setup for playing an audio file works; I have another app I am building that uses the exact same setup. Why does it tell me that I unwrap nil here: http://a1993.phobos.apple.com/us/r1000/101/Music/b7/b3/e0/mzm.ooahqslp.aac.p.m4a? The url is valid and the file plays.
Examine this line of code.
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(url, ofType: "m4a")!)
fileUrlWithPath is asking for a local path, that is one on your device.
NSBundle.mainBundle().pathForResource(url.....
This method returns the local path for the resource you send to it. You are sending it a web url, which is not in the mainBundle unless you've explicitly put it there. So the path that it returns is nil, because there is no local path that satisfies the arguments you are passing to it.
If you have a local resource you should use a method called URLForResource
This line makes no sense. You should always prefer working with urls and extract the path from it if needed.
Replace this line:
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("fileName", ofType: "m4a")!) // this would crash if not found (nil)
with this block of code
if let alertSoundUrl = NSBundle.mainBundle().URLForResource("fileName", withExtension: "m4a") {
println(true)
} else {
println(false)
}
If it is a web link you need to use NSURL(string:). fileUrlWithPath it is only for local resources.
if let checkedUrl = NSURL(string: "http://a1993.phobos.apple.com/us/r1000/101/Music/b7/b3/e0/mzm.ooahqslp.aac.p.m4") {
println(true)
} else {
println(false)
}