String nil inside NSURLSession
The reason your variable is nil is because closures are executed asynchronously. That means that the rest of the code after the network request will continue to be called as normal, but the code containing parameters data, response and error is only called when the network request is finished.
To work around this, try putting whatever you are trying to do with the variable inside the closure, so your println(testString)
would be inside the curly brackets.
Why does NSHTTPURLResponse return nil? NSURLSession, Swift 2.2
func dataTaskWithRequest(_ request: NSURLRequest,
completionHandler completionHandler: (NSData?,
NSURLResponse?,
NSError?) -> Void) -> NSURLSessionDataTask
The initial method takes an NSURLResponse
. This is the response of the requested URL. NSURLResponse
can be of any kind of response.
NSHTTPURLResponse
is a subclass of NSURLResponse
, you can cast your response to NSHTTPURLResponse
only if you are sure that your webservice encode responses using the HTTP protocol. Otherwise, the cast will always return nil
.
Also, I'm seeing that the Webservice that you are using has some restrictions of usage :
How to get accurate API response
1 Do not send requests more then 1 time per 10 minutes from one device/one API key. Normally the weather is not changing so
frequently.2 Use the name of the server as api.openweathermap.org. Please never
use the IP address of the server.3 Call API by city ID instead of city name, city coordinates or zip
code. In this case you get precise respond exactly for your city.4 Free account has limitation of capacity and data availability. If
you do not get respond from server do not try to repeat your
request immediately, but only after 10 min. Also we recommend to store
your previous request data.
Now I'm thinking that your problem could come from there.
URL nil after upgrade to swift 3.0
Try this:
let firstResult = "San Francisco, California, United States"
print(firstResult)
if let correctedAddress = firstResult.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: "https://maps.googleapis.com/maps/api/geocode/json?address=\(correctedAddress)") {
print(url)
}
NSURLSession crash with JSON data parameter is nil while error is managed
You should just add a if block after before initizaling your JSON. Such as:
if(rawData != nil) {
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:dataRaw
options:kNilOptions error:&error];
}
After that you can handle your error if it is not nil.
Swift / NSURLSession JSON download / unexpectedly found nil while unwrapping an Optional value
Your problem is in these 2 lines:
let dollarToDollarNSNumber = dollarToDollarDict.valueForKey("EUR")
let dollarToDollarString = String(dollarToDollarNSNumber)
dollarToDollarDict.valueForKey("EUR")
returns an optional, so dollarToDollarNSNumber
is an optional.
Calling the String
initializer with an optional gives the string "Optional(...)"
so when you later pass that string to the Double
initializer it fails because it has letters in it.
You need to unwrap the value you get from valueForKey
by doing something like this:
if let dollarToDollarNSNumber = dollarToDollarDict.valueForKey("EUR") {
let dollarToDollarString = String(dollarToDollarNSNumber)
SpeedLog.print(dollarToDollarString)
self.dollarExchangeRateStr = dollarToDollarString
} else {
self.dollarExchangeRateStr = ""
}
Why my return is nil but if i press the url in chrome/safari, i can get data?
The text you try to get is probably not UTF-8, try with another encoding, like this for example:
let myString = NSString(data: data, encoding: NSASCIIStringEncoding)
Update: read Martin R's answer for how to find the right encoding.
NSURLSession Response String completion block - Swift
The convenience method of dataTaskWithRequest essentially returns data or error, with usually some response header type information. If you have an error then you won't have data (99% sure about this). I have re formatted your method to help. The NSString Init Convenience method is synchronous so not quite sure by what you mean by waiting to complete instead of http call?
func getStringFromRequest(completionHandler:(success:Bool, data: NSData?) -> Void) {
let request = NSMutableURLRequest(URL: NSURL(string: "http://##.##.##.##/EPG/XML/QueryProfile")!)
request.HTTPMethod = "POST"
let postString = "<QueryProfileReq><type>1</type></QueryProfileReq>"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
if let unwrappedError = error {
print("error=\(unwrappedError)")
}
else {
if let unwrappedData = data {
completionHandler(success: true, data: unwrappedData)
return
}
}
completionHandler(success: false, data: nil)
}
task?.resume()
}
func performPost() {
getStringFromRequest { (success, data) -> Void in
if (success) {
if let unwrappedData = data {
self.dataVar = unwrappedData
if let responseString = NSString(data: unwrappedData, encoding: NSUTF8StringEncoding) {
self.nextScreen()
}
}
}
else {
print("Failed")
}
}
}
Return value in NSURLSession Error
You can use this method with block like this :
-(void)callAPIWithCompletionHandler : (void (^) (NSString * strResponse)) completionHandler
{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:@"http://appersgroup.com/talkawalk/login.php?email=twalknet@gmail.com&password=123456&latitude=52.486245&longitude=13.327496&device_token=show"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPMethod:@"POST"];
/* NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: @"TEST IOS", @"name",
@"IOS TYPE", @"typemap",
nil];
NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
[request setHTTPBody:postData];
*/
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString* responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if([responseString rangeOfString:@"nil"].location != NSNotFound)
{
NSString * newResponse = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
responseString = newResponse;
}
NSLog(@"%@",responseString);
NSLog(@"response %@",response);
NSLog(@"error %@",error);
completionHandler(responseString);
}];
[postDataTask resume];
}
Call this method and return response as below :
[self callAPIWithCompletionHandler:^(NSString *strResponse) {
NSString *responseString = strResponse;
}];
Suppose this method implemented in ViewControllerA
, and you want to call this from ViewControllerB
.
Then import ViewControllerA
in ViewControllerB
and make instance of ViewControllerA
in ViewControllerB
.
ViewControllerA *vcA = [[ViewControllerA alloc] init];
[vcA callAPIWithCompletionHandler:^(NSString *strResponse) {
NSString *responseString = strResponse;
}];
Related Topics
iOS 8 Swift Audio Playback Execute Method on Completion
Linking Error When Building Parse in Xcode 7
Updated Approach to Reauthenticate a User
"Ambiguous Use of 'Children'" When Trying to Use Nstreecontroller.Arrangedobjects in Swift 3.0
How to Stop an Infinitely Rotating Image? and How Does One Implement Removeallanimations
Swift: How to Invalidate a Timer If the Timer Starts from a Function
How to Filter Nsarray in Swift
Datefromstring() Returns Incorrect Date
Convert Swift Encodable Class Typed as Any to Dictionary
Switch Statement for Imported Ns_Options (Rawoptionsettype) in Swift
How to Run App in Simulator Xcode 6
How to Display Mtkview with Rgba16Float Mtlpixelformat
Swift Package Manager with Resources Compile Errors
Differences Between Ways of Initializing a Dictionary