How to send some count of POST/GET requests simultaneously? - xcode

I'm learning swift, trying to send 2 and more requests not one by one, but simultaneously. Is it possible with NSURLSession?

NSURLSession is asynchronous which means it is sent on a different thread and can be run multiple at once.
This link explains and gives an example on how to handle the response back on the main thread etc:
https://www.raywenderlich.com/110458/nsurlsession-tutorial-getting-started
func sendRequest() {
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
var dataTask: NSURLSessionDataTask?
let url = NSURL(string: "http://www.url.com")
dataTask = defaultSession.dataTaskWithURL(url!) {
data, response, error in
dispatch_async(dispatch_get_main_queue()) {
//Handle response
if let error = error {
//Error - handle 'error'
print(error.localizedDescription)
} else if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode == 200 {
//Success - handle 'data'
}
}
}
}
dataTask?.resume()
}
Hope this helps

Related

URL Sessions returning server not found even though URL is valid - Swift4

I am trying to use URLSession to do a API Request. The request/link is the following https://api.nanopool.org/v1/zec/user/t1KcroGeTYz6Tn4hsgwnuiUzw65xgAAaknc
When I put it into safari it loads. When I try preform the request in Xcode 9 with Swift4, I get an error that the server was not found.
Here is the entire error.
The top to lines are just from a print function, the rest is the error.
Here is the code I used:
let api = "https://api.nanopool.org/v1/zec/user/"
let urlString = api+addr
print(urlString)
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
print(data)
}.resume()
What is the issue with it that it causing it to return that the server cannot be found even though its a valid URL/Request?

Swift URL POST request function with returning values [duplicate]

I am currently trying to download, parse and print JSON from an URL.
So far I got to this point:
1) A class (JSONImport.swift), which handles my import:
var data = NSMutableData();
let url = NSURL(string:"http://headers.jsontest.com");
var session = NSURLSession.sharedSession();
var jsonError:NSError?;
var response : NSURLResponse?;
func startConnection(){
let task:NSURLSessionDataTask = session.dataTaskWithURL(url!, completionHandler:apiHandler)
task.resume();
self.apiHandler(data,response: response,error: jsonError);
}
func apiHandler(data:NSData?, response:NSURLResponse?, error:NSError?)
{
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
catch{
print("API error: \(error)");
}
}
My problem is, that the data in
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
remains empty.
When I debug,the connection starts successfully, with the given url as a parameter. But my jsonData variable doesn't get printed. Instead the catch block throws the error, stating that there is no data in my variable:
API error: Error Domain=NSCocoaErrorDomain Code=3840 "No value."
Can someone please help me with this?
What am I missing?
Thank you all very much in advance!
[Edited after switching from NSURL Connection to NSURLSession]
Here's an example on how to use NSURLSession with a very convenient "completion handler".
This function contains the network call and has the "completion handler" (a callback for when the data will be available):
func getDataFrom(urlString: String, completion: (data: NSData)->()) {
if let url = NSURL(string: urlString) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (data, response, error) in
// print(response)
if let data = data {
completion(data: data)
} else {
print(error?.localizedDescription)
}
}
task.resume()
} else {
// URL is invalid
}
}
You can use it like this, inside a new function, with a "trailing closure":
func apiManager() {
getDataFrom("http://headers.jsontest.com") { (data) in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let jsonDict = json as? NSDictionary {
print(jsonDict)
} else {
// JSON data wasn't a dictionary
}
}
catch let error as NSError {
print("API error: \(error.debugDescription)")
}
}
}

This application is modifying the autolayout engine from a background thread, which can lead to engine corruption

I am getting this error This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes.This will cause an exception in a future release. I don't know what is causing this error. Can anybody help me.
func getUserDataFromTwitterWithUser(user : PFUser)
{
//NRLoader.showLoader()
let strTwURL = "https://api.twitter.com/1.1/users/show.json? screen_name="+PFTwitterUtils.twitter()!.screenName! + "&access_token="+PFTwitterUtils.twitter()!.authToken!
let twURL = NSURL (string: strTwURL)
let request = NSMutableURLRequest(URL: twURL!, cachePolicy: NSURLRequestCachePolicy.UseProtocolCachePolicy, timeoutInterval: 2.0) as NSMutableURLRequest
PFTwitterUtils.twitter()?.signRequest(request)
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if error == nil {
var jsonOptional = Dictionary<String, AnyObject>()
do {
jsonOptional = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers ) as! Dictionary<String, AnyObject>
// use jsonData
} catch {
// report error
}
var userName = ""
if let screenName = jsonOptional["screen_name"] as? String{
userName = screenName
}
else if let name = jsonOptional["name"] as? String{
userName = name
}
var profilePicUrl = ""
if let picUrl = jsonOptional["profile_image_url"] as? String{
profilePicUrl = picUrl
}
AppUser.currentUser()?.username = userName
AppUser.currentUser()?.profileAwsURL = profilePicUrl
//NRLoader.hideLoader()
//if ParseUtils.isLoggedInUserIsAnonymous() {
let signUpVC:SignMeUpViewController = self.storyboard!.instantiateViewControllerWithIdentifier("SignMeUpViewController") as! SignMeUpViewController
signUpVC.isFromLogin = true
self.navigationController!.pushViewController(signUpVC, animated: true)
//} else {
// self.pushToSubmitDreamViewController()
//}
}
else {
//NRLoader.hideLoader()
NRToast.showToastWithMessage(error!.description)
}
}).resume()
}
The dataTaskWithRequest call runs in the background and then calls your completion handler from the same thread. Anything that updates the UI should run on the main thread, so all of your current handler code should be within a dispatch_async back onto the main queue:
dispatch_async(dispatch_get_main_queue()) {
// Do stuff to UI
}
Swift 3:
DispatchQueue.main.async() {
// Do stuff to UI
}
Therefore, ideally all the code you currently have within if error == nil should be off in another function, say called handleRequest, so your current code becomes:
session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if error == nil {
dispatch_async(dispatch_get_main_queue(), {
self.handleRequest(...)I
})
}
Swift 3
session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if error == nil {
DispatchQueue.main.async {
self.handleRequest(...)I
}
}
Should try Symbolic Breakpoint to detect the issue:-
Then put your UI Update code in main thread
DispatchQueue.main.async {}
You'd better change UI only in the main thread
swift3,
let liveInfoUrl = URL(string: "http://192.168.1.66/api/cloud/app/liveInfo/7777")
let task = URLSession.shared.dataTask(with: liveInfoUrl! as URL) {data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
print(String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) ?? "aaaa")
//do some ui work
}
}
if the above suggestions still give you no joy then the sure-est way is to redesign your functions so that getting what you need with
URLSession.shared.dataTask
then hands over so a variable declared outside that function, then a separate UIControl ( button, swipe etc ) displays it to a label or textview or whatever.
After all that is what the error message is telling you. they're separate concerns

Can't make Alamofire run in the simulator

i have installed alamo fire and cannot seem to make a request with it.
#IBAction func loginButtonTapped(sender: UIButton) {
let groupLogin = groupUserNameEntry.text;
let groupPassword = groupPasswordEntry.text;
print("line of debug code before request")
Alamofire.request(.GET, "http://api.myserver.com/folks/authenticate", parameters: ["login": groupLogin!, "password": groupPassword!])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
print("line of debug code inside request")
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
when run in the simulator i get the first line of debug code before request but the output in the "All Output" viewer is (lldb), which i understand to mean low level debugger. It seems like the request is not getting made, but there is no error output. The url works fine in a browser.
The text of a UITextField is an optional value, so what you are doing is assigning to groupLogin an optional value, but groupLogin is not an optional value type, so everything breaks.
You need to safely unwrap optional values, there're many ways to achieve this, but in my opinion guard is the best:
#IBAction func loginButtonTapped(sender: UIButton) {
guard let groupLogin = groupUserNameEntry.text else {
print("groupUserNameEntry.text is nil, stop execution")
return
}
guard let groupPassword = groupPasswordEntry.text else {
print("groupPasswordEntry.text is nil, stop execution")
return
}
print("line of debug code before request")
Alamofire.request(.GET, "http://api.myserver.com/folks/authenticate", parameters: ["login": groupLogin, "password": groupPassword])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
print("line of debug code inside request")
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}

Swift URL Response is nil

I have created a custom DataManager class. Inside it I want to fetch data in a method and return an NSData object to convert to JSON afterwards.
I have tried to get the data using the completionHandler but no luck:
class func fetchData() -> NSData? {
var session = NSURLSession.sharedSession(),
result = NSData?()
let DataURL : NSURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(DataURL, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
result = data
})
sessionTask.resume()
return result
}
The dataTask runs asynchronously. That means that the completion handler closure will not be called by the time you return from fetchData. Thus, result will not have been set yet.
Because of this, you should not try to retrieve data synchronously from an asynchronous method. Instead, you should employ an asynchronous completion handler pattern yourself:
class func fetchData(completion: #escaping (Data?, Error?) -> Void) {
let session = URLSession.shared
let url = URL(string: "http://...file.json")!
let task = session.dataTask(with: url) { data, response, error in
completion(data, error)
}
task.resume()
}
And you'd call it like so:
MyClass.fetchData { data, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
// use `data` here; remember to dispatch UI and model updates to the main queue
}
// but do not try to use `data` here
...
FYI, for the original pre-Swift 3 syntax, see previous revision of this answer.

Resources