2

I have researched the last few hours and cannot find an example that works in iOS 9 in my Swift application. I simply want to do an HTTP GET request to a url "http://www.example.com". The URL will return XML data that will be parsed but for now I just want to get the HTTP GET command to run.

I am new to Xcode but have some programming background but cannot figure out how to get a URL to do a GET command

I have a button that I have and I want it to run the HTTP GET request when the button is pressed. When looking through the NSURLSession examples online, I cannot find one that won't throw a syntax error. Any help would be appreciated. Below is one I found but its throwing a bunch of errors. Any guidance would be appreciated.

import Foundation
import XCPlayground
func httpGet(request: NSURLRequest!, callback: (String, String?) -> Void) {
    var session = NSURLSession.sharedSession()
    var task = session.dataTaskWithRequest(request){
        (data, response, error) -> Void in
        if error != nil {
            callback("”, error.localizedDescription),
        } else {
            var result = NSString(data: data, encoding:
                NSASCIIStringEncoding)!
            callback(result, nil)
        }
    }
    task.resume()
}
var request = NSMutableURLRequest(URL: NSURL(string: “http://www.google.com")!)

httpGet(request){
    (data, error) -> Void in
    if error != nil {
        println(error)
    } else {
        println(data)
    }
}
XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
Seth Haberman
  • 131
  • 1
  • 13

2 Answers2

1

A cleaned-up, Swift 2 rendition of your code sample might look like:

import Foundation
import XCPlayground

func httpGet(request: NSURLRequest, callback: (String?, NSError?) -> Void) {
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
        guard error == nil && data != nil else {
            callback(nil, error)
            return
        }

        callback(String(data: data!, encoding: NSUTF8StringEncoding), nil)
    }
    task.resume()
}

let request = NSMutableURLRequest(URL: NSURL(string: "http://www.google.com")!)

httpGet(request) { string, error in
    guard error == nil && string != nil else {
        print(error?.localizedDescription)
        return
    }

    print(string!)
}

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

This fixes the obvious errors in the original code snippet (the occasional use of and instead of "; the use of the deprecated println rather than print; the extraneous , after the first callback call; add some missing optional unwrapping; etc.).

This also addresses a few other issues, namely,

  • Use String rather than NSString;
  • Make String parameter of callback optional (rather than returning "" when there was an error);
  • I think it's preferable to return the the actual NSError object rather than just the localized description (at some point, you might actually care about the code or domain of the error)
  • Use of Swift 2 guard statements to guard against any errors that occur.
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • That did it! Thanks so much! Wow, after 4 hours I finally got it to work! Now off to parsing the return XML into variables. . . – Seth Haberman Oct 25 '15 at 06:44
0

Here's a GET method I use:

func get(url : String, successHandler: (response: String) -> Void) {
    let url = NSURL(string: url)
    let request = NSMutableURLRequest(URL: url!);
    request.HTTPMethod = "GET"

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        //in case of error
        if error != nil {
            return
        }

        let responseString : String = String(data: data!, encoding: NSUTF8StringEncoding)!
        successHandler(response: responseString)
    }
    task.resume();
}

Since you're making a plain HTTP request, you need to modify your Info.plist file. Add the following key after the last array element if your file was created from the default template (as in a new single view application for example).

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>google.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
        </dict>
    </dict>
</dict>

A less secure approach that allows for an arbitrary number of domains:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
      <true/>
</dict>

Finally, you can test the above method in the viewDidLoad() function along with any callback. I called my callback updateWebview but yours can be called anything of course.

override func viewDidLoad() {
    super.viewDidLoad()
    let url = "http://www.google.com"
    get(url, successHandler: {(response) in self.updateWebview(response)});
}

func updateWebview(let html: String) {
    print(html)
}

An example that uses POST with parameters:

func post(url : String, params : String, successHandler: (response: String) -> Void) {
    let url = NSURL(string: url)
    let params = String(params);
    let request = NSMutableURLRequest(URL: url!);
    request.HTTPMethod = "POST"
    request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        //in case of error
        if error != nil {
            return
        }

        let responseString : String = String(data: data!, encoding: NSUTF8StringEncoding)!
        successHandler(response: responseString)
    }
    task.resume();
}
ThisClark
  • 14,352
  • 10
  • 69
  • 100
  • This could be a problem with the Info.plist. The issue is that the http request could be going to any IP address that I will have the user define depending on their system. How would you add the rule if you didn't know what the domain would be? – Seth Haberman Oct 25 '15 at 06:52
  • Never mind, I figured it out http://stackoverflow.com/questions/32631184/the-resource-could-not-be-loaded-because-the-app-transport-security-policy-requi – Seth Haberman Oct 25 '15 at 07:00