Can't use variable outside of scope method in Swift (dataTaskWithRequest) - ios

#IBOutlet var nameLabel : UILabel!
var finalString: String = "test"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func helloWorldAction(nameTextField: UITextField) {
//fetch data from server
let request = NSMutableURLRequest(URL: NSURL(string: "http://192.168.1.11")!)
request.HTTPMethod = "POST"
let postString = "user=test&pass=test3"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
//error handeling
if error != nil {
println("error=\(error)")
return
}
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
self.finalString = String(responseString!)
println("\(self.finalString)");
}
task.resume()
//print finalString
println("finalString = \(finalString)")
}
}
I am trying to do two things, and I will tell you what isn't working with both.
First, not seen in this code, I was trying to assign a UILabel.text a value, that didn't work at all. I couldn't do it within the function and neither could I do it outside. This brings me to problem number two. When finalString is printed inside the function it outputs the proper value.
However, when its printed outside the function it prints the value it was first assigned. Please tell me how to assign the UILabel.text a value properly and how to use the output outside of the scope of the questions.
Thanks in advance.

import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameLabel: UITextField!
// you have to add a completion block to your asyncronous request
func fireRequest(link:String,completion: ((data: NSData?) -> Void)) {
if let requestUrl = NSURL(string: link){
let request = NSMutableURLRequest(URL: requestUrl)
request.HTTPMethod = "POST"
let postString = "user=test&pass=test3"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
completion(data: NSData(data: data))
if let error = error {
println("error=\(error)")
return
}
}.resume()
}
}
override func viewDidLoad() {
super.viewDidLoad()
println("Fired request" + NSDate().description )
fireRequest("http://192.168.1.11") { data in
dispatch_async(dispatch_get_main_queue()) {
println("Finished request")
if let data = data { // unwrap your data (!= nil)
let myResponseStr = NSString(data: data, encoding: NSUTF8StringEncoding) as String
self.nameLabel.text = myResponseStr
println("response:"+myResponseStr)
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Related

How to display YouTube search API response in UI text view?

I am creating a project where I have to display the YouTube search API response in a UI Text View when a button is clicked. Now I am getting the response in console.
1) How to display it as a JSON response.
2) How to display it in UI text view.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var resultTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func goButton(_ sender: Any) {
guard let url = URL(string: "https://www.youtube.com/watch?v=6Zf79Ns8_oY")else {
return
}
let session = URLSession.shared
let task = session.dataTask(with: url) {(data, response, error) in
if let response = response {
print(response)
}
if let jsondata = data {
print(jsondata)
}
}
task.resume()
}
}
I think you are looking for that:
Parse Response using JSONSerialization and set required value to textview text.
guard let url = URL(string: "https://www.youtube.com/watch?v=6Zf79Ns8_oY")else {
return
}
let session = URLSession.shared
let task = session.dataTask(with: url) {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let text = json["KEY"] as? String
DispatchQueue.main.async{
self.YOURTEXTVIEW.text = text
}
} catch let error as NSError {
print(error)
}
}
task.resume()
maybe it is helpful.

Labels in viewcontroller are populated very slow

I'm struggling with extreme slow population of the labels in my viewcontroller.
The script sends a userid to a php script. To script retrieves data related to the userid in an array and sends it back as a json response to my app. Then the labels in my viewcontroller are populated with the corresponding data from the json array (dictionary).
the print statements in the "do{}" are executed immediately in the console, but the population of the labels in the viewcontroller takes ages. Putting self.lblStreet.text = self.loadedStreet outside do{}, but still in the task, it gives the same slow result.
class CharDetailViewController: UIViewController {
//Outlets
#IBOutlet weak var lblUID: UILabel!
#IBOutlet weak var lblStreet: UILabel!
//URL to our web service
let URL_GET_DETAILS = "http://somesite.com/script.php"
var passedUID: String!
var loadedStreet: String!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: URL_GET_DETAILS)
lblUID.text = passedUID
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST";
let sendUID = lblUID.text
let postParameters = "sendUID="+sendUID!;
request.httpBody = postParameters.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with:request as URLRequest){
data, response, error in
if error != nil{
print("error is \(error)")
return;
}
do{
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = myJSON {
var uid : String!
uid = parseJSON["userid"] as! String?
self.loadedStreet = parseJSON["street"] as! String!
self.lblStreet.text = parseJSON["street"] as! String!
print(uid)
print(self.loadedStreet)
}
}
catch {
print(error)
}
}
task.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Update your UI on the main thread. URLSession has you in a background thread. The appropriate code in Swift 3 is
DispatchQueue.main.async {
//your UI code
}
So your code should look more like this.
class CharDetailViewController: UIViewController {
//Outlets
#IBOutlet weak var lblUID: UILabel!
#IBOutlet weak var lblStreet: UILabel!
//URL to our web service
let URL_GET_DETAILS = "http://somesite.com/script.php"
var passedUID: String!
var loadedStreet: String!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: URL_GET_DETAILS)
lblUID.text = passedUID
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST";
let sendUID = lblUID.text
let postParameters = "sendUID="+sendUID!;
request.httpBody = postParameters.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with:request as URLRequest){
data, response, error in
if error != nil{
print("error is \(error)")
return;
}
do{
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = myJSON {
var uid : String!
uid = parseJSON["userid"] as! String?
DispatchQueue.main.async {
//your UI code
self.loadedStreet = parseJSON["street"] as! String!
self.lblStreet.text = parseJSON["street"] as! String!
}
print(uid)
print(self.loadedStreet)
}
}catch {
print(error)
}
}
task.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You shouldn't edit the UI anywhere other than the main thread. You can use this code to get the main thread in order to implement UI updates.
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI stuff here
});

Web View Not Displaying Content in Swift 2.0

I was following a tutorial to display content from a web view within my application. In swift 2.0, when I run the emulator I am getting no response on the emulator screen.
My code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "http://www.stackoverflow.com")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {
(data, response, error) in
if error == nil {
var urlContent = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(urlContent)
dispatch_async(dispatch_get_main_queue()) {
self.webView.loadHTMLString(urlContent! as String, baseURL: nil)
}
}
}
task.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I'm pretty sure you should try to retain your data task.
Just declare stored property:
var task: NSURLSessionDataTask?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "http://www.stackoverflow.com")
task = NSURLSession.sharedSession().dataTaskWithURL(url!) {
(data, response, error) in
if error == nil {
var urlContent = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(urlContent)
dispatch_async(dispatch_get_main_queue()) {
self.webView.loadHTMLString(urlContent! as String, baseURL: nil)
self.task = nil
}
}
}
task.resume()

Why do I need to use dispatch_async I think I am on the same thread

I have a login page in IOS using swift. When I click the SignIn button I start the login process that calls a function with delegate call backs on completion. This works fine, and my activity indicator starts spinning. The issue is, that when I get my delegate callbacks and I call the stopanimating() on the indicator it does not stop until about 6 seconds later. If I add the dispatch_async, it will stop animating right away. This makes me believe that I am not running on the same thread, but I do not see where this is happening.
EDIT: It looks like when I am calling in my Rest Function session.dataTaskWithRequest() that the block of code that is returned is not on the main thread, so when I call the delegates and return to the main code, it is not on the main thread? Is this correct? I can't find documentation that would explain that.
class Login_ViewController: UIViewController, RestServiceDelegate {
#IBOutlet weak var txtEmail: UITextField!
#IBOutlet weak var txtPassword: UITextField!
#IBOutlet weak var signInActivity: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func signInClick(sender: UIButton) {
signInActivity.startAnimating()
var restReq = RestRequest()
restReq.delegate = self
var restParams = ["userEmail":"\(txtEmail.text)", "password":"\(txtPassword.text)"] as Dictionary<String, String>
restReq.callRestAction(restParams, restAction: "AuthenticateUser")
}
func stopActivity()
{
println("Stopping the Activity Indiciator")
// WHY DOES THIS LINE TAKE FOREVER TO STOP ANIMATING?
self.signInActivity.stopAnimating()
// IF I UNCOMMENT THIS NEXT LINE IT WILL STOP THE ANIMATION!
//dispatch_async(dispatch_get_main_queue() , {self.signInActivity.stopAnimating()})
}
// MARK: - RestServiceDelegate
func restServiceEndedWithError(message : String, calledRestAction : String) {
stopActivity()
println("Error with Rest Request: \(message) for Action: \(calledRestAction)")
}
func restServiceResponse(jsonResponse : NSDictionary, calledRestAction : String) {
println("Response from Rest Request \(calledRestAction) with data \(jsonResponse)")
if let userAuth : AnyObject = jsonResponse["AuthenticateUserResult"] {
if userAuth as! Bool == true
{
println("User Authenticated: \(userAuth).")
}
else
{
println("Not Authenticated")
}
} else {
println("Not Authenticated")
}
stopActivity()
}
}
Here is the code when calling the Rest Action:
protocol RestServiceDelegate
{
func restServiceResponse(jsonResponse : NSDictionary , calledRestAction : String)
func restServiceEndedWithError(message : String, calledRestAction : String)
}
class RestRequest
{
let appToken : String = "blah blah blah"
let restURL : String = "http://blah blah blah"
var delegate : RestServiceDelegate?
func callRestAction(params : Dictionary<String,String>, restAction : String )
{
var url : String = restURL + restAction
println("CALLING REST URL: \(url)")
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "POST"
var session = NSURLSession.sharedSession()
var newParams = params
newParams.updateValue(appToken, forKey: "appToken")
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(newParams, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData : String = (NSString(data: data, encoding: NSUTF8StringEncoding) as? String)!
println("Returned Result (BODY): \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
if(err != nil)
{
self.delegate!.restServiceEndedWithError(err!.localizedDescription, calledRestAction: restAction)
}
else
{
self.delegate!.restServiceResponse(json!, calledRestAction: restAction)
}
})
task.resume()
}
}

Swift - Return data from NSURLSession when sending POST request

I can send a POST request in Swift using the below code
func post() -> String{
let request = NSMutableURLRequest(URL: NSURL(string: "http://myserverip/myfile.php")!)
request.HTTPMethod = "POST"
let postString = "data=xxxxxxx"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
println("response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString!)")
}
task.resume()
return "";//how would i return data here
}
I need to return the result, but this isn't possible since the network request is asynchronous. I think I can use a listener to wait for the result and then return it, but I'm not sure how this would work or how to implement it
If anyone could help, I would greatly appreciate it
I am new to both iOS and Swift
Your post function might be like:
func post(completionHandler: (response: String) -> ()) { your code }
And in the response part:
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
completionHandler(response: responseString)
Finally, you can call your post method like:
post( {(response: String) -> () in
println("response = \(response)")})
You can use a delegate or pass a function as an argument of post that you call at the end
Example with a completion handler :
struct RemoteCenter {
static func post(completion: (message: String?) -> Void) {
let request = NSMutableURLRequest(URL: NSURL(string: "http://myserverip/myfile.php")!)
request.HTTPMethod = "POST"
let postString = "data=xxxxxxx"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
completion(message: NSString(data: data, encoding: NSUTF8StringEncoding) as? String)
}
task.resume()
}
}
class YourController: UIViewController {
override func viewDidLoad() {
RemoteCenter.post(completionHandler)
}
func completionHandler(message: String?){
println("I got \(message)")
}
}
Example with a delegate :
protocol DelegateProtocol {
func didReceiveAMessage(message: String?)
}
struct RemoteCenter {
var delegate:DelegateProtocol?
func post() {
let request = NSMutableURLRequest(URL: NSURL(string: "http://myserverip/myfile.php")!)
request.HTTPMethod = "POST"
let postString = "data=xxxxxxx"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
self.delegate?.didReceiveAMessage(NSString(data: data, encoding: NSUTF8StringEncoding) as? String)
}
task.resume()
}
}
class YourController: UIViewController, DelegateProtocol {
var remote = RemoteCenter()
override func viewDidLoad() {
remote.delegate = self
remote.post()
}
func didReceiveAMessage(message: String?) {
println("I got \(message)")
}
}
In both cases, the goal is to fetch some data on the internet from an UIViewController and print the message when it's done.
You can find so many tutorials about it. Check http://www.raywenderlich.com

Resources