43

I'm trying to get the JSON from a website and parse it before putting it inside of an iOS view.

Here's my code;

func startConnection(){
        let urlPath: String = "http://binaenaleyh.net/dusor/"
        var url: NSURL = NSURL(string: urlPath)
        var request: NSURLRequest = NSURLRequest(URL: url)
        var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)
        connection.start()
    }

    func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
        self.data.appendData(data)
    }

    func buttonAction(sender: UIButton!){
        startConnection()
    }

    func connectionDidFinishLoading(connection: NSURLConnection!) {
        var err: NSError
        // throwing an error on the line below (can't figure out where the error message is)
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
    }

And this is the link for the JSON;

http://binaenaleyh.net/dusor/

What am I doing wrong here?

James Webster
  • 31,873
  • 11
  • 70
  • 114
Çağdaş Salur
  • 1,360
  • 3
  • 14
  • 24

9 Answers9

34

These two functions worked for me:

    func getJSON(urlToRequest: String) -> NSData{
        return NSData(contentsOfURL: NSURL(string: urlToRequest))
    }

    func parseJSON(inputData: NSData) -> NSDictionary{
        var error: NSError?
        var boardsDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(inputData, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary

        return boardsDictionary
    }
Çağdaş Salur
  • 1,360
  • 3
  • 14
  • 24
  • 3
    It doesn't look like the parseJSON function works properly if the origin JSON is wrapped in an array – Pirijan Jul 01 '14 at 18:29
  • 9
    You should not use `NSData:contentsOfURL` as it is a blocking call. Use the `NSURLConnectionDelegate` protocol as eXhausted shows above. Alternatively you can use the newer `NSURLSession` api to download data. Take a look at the docs for examples. – Ben Scheirman Jul 12 '14 at 13:47
  • 4
    @Zorayr it's almost never ok to block. This API doesn't give you any control over how the connection is handled, the response is handled, completely blocks the thread from doing anything else. What if you're on a slow/bad connection and this times out? What if the resource is not found? What if the connection is interrupted? What if you want to cancel the request? – Ben Scheirman Apr 26 '15 at 16:13
26

UPDATE: Swift 4

// Asynchronous Http call to your api url, using URLSession:
URLSession.shared.dataTask(with: URL(string: "http://api.site.com/json")!) { (data, response, error) -> Void in
    // Check if data was received successfully
    if error == nil && data != nil {
        do {
            // Convert to dictionary where keys are of type String, and values are of any type
            let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: Any]
            // Access specific key with value of type String
            let str = json["key"] as! String
        } catch {
            // Something went wrong
        }
    }
}.resume()

Here is how to do it with Swift 2 and NSURLSession:

// Asynchronous Http call to your api url, using NSURLSession:
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://api.site.com/json")!, completionHandler: { (data, response, error) -> Void in
    // Check if data was received successfully
    if error == nil && data != nil {
        do {
            // Convert NSData to Dictionary where keys are of type String, and values are of any type
            let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [String:AnyObject]
            // Access specific key with value of type String
            let str = json["key"] as! String
        } catch {
            // Something went wrong
        }
    }
}).resume()
david72
  • 7,151
  • 3
  • 37
  • 59
24

This code works fine for me. Just init data property with data = NSMutableData() and write NSURLConnectionDelegate here class ViewController: UIViewController, NSURLConnectionDelegate

import UIKit

class ViewController: UIViewController, NSURLConnectionDelegate {

    @lazy var data = NSMutableData()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        startConnection()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func startConnection(){
        let urlPath: String = "http://binaenaleyh.net/dusor/"
        var url: NSURL = NSURL(string: urlPath)
        var request: NSURLRequest = NSURLRequest(URL: url)
        var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)
        connection.start()
    }

    func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
        self.data.appendData(data)
    }

    func buttonAction(sender: UIButton!){
        startConnection()
    }

    func connectionDidFinishLoading(connection: NSURLConnection!) {
        var err: NSError
        // throwing an error on the line below (can't figure out where the error message is)
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        println(jsonResult)
    }
}

here is output:

{
    "ders sayisi" = 15;
    dersler =     (
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 2;
            12 = "";
            2 = 2;
            3 = "CEE 102";
            4 = "Logic Circuits";
            5 = 3;
            6 = "6.00";
            7 = "YRD.DO\U00c7.DR.INDRIT MYDERRIZI";
            8 = 0;
            9 = IA;
        },
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 1;
            12 = "";
            2 = 2;
            3 = "CIP 102";
            4 = "Civic Involment Projects";
            5 = 0;
            6 = "2.00";
            7 = "SE\U00c7\U0130L AVCI/BA\U015eAK CANSU AK\U00c7EL\U0130K/\U00c7A\U011eLA UNGUN";
            8 = 0;
            9 = P;
        },
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 2;
            12 = "";
            2 = 2;
            3 = "COME 108";
            4 = "Algorithms and Programming II";
            5 = 3;
            6 = "6.00";
            7 = "\U00d6\U011eR.G\U00d6R.DR.B\U0130RSEN G\U00dcLDEN \U00d6ZDEM\U0130R";
            8 = 41;
            9 = C;
        },
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 1;
            12 = "";
            2 = 2;
            3 = "COME 335";
            4 = "Mobile Application Development";
            5 = 3;
            6 = "5.00";
            7 = "\U00d6\U011eR.G\U00d6R.OZAN UYSAL";
            8 = TeacherHold;
            9 = TeacherHold;
        },
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 1;
            12 = "";
            2 = 2;
            3 = "ENG 112";
            4 = "Advanced English For Engineering and Natural Sciences I";
            5 = 2;
            6 = "3.00";
            7 = "OKT.ERIC BEECHER";
            8 = 48;
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 1;
            12 = "";
            2 = 2;
            3 = "PHYS 102";
            4 = "Physics II";
            5 = 4;
            6 = "5.00";
            7 = "YRD.DO\U00c7.DR.\U00d6ZG\U00dcL KURTULU\U015e \U00d6ZT\U00dcRK";
            8 = "-1";
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = BAHAR;
            10 = TeacherHold;
            11 = 2;
            12 = "";
            2 = 2;
            3 = "T\U00dcRK 102";
            4 = "T\U00fcrk Dili II";
            5 = 2;
            6 = "2.00";
            7 = "\U00d6\U011eR.G\U00d6R.\U015eER\U0130FE GEZG\U0130N";
            8 = 10;
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 2;
            12 = "";
            2 = 1;
            3 = "CHEM 101";
            4 = Chemistry;
            5 = 3;
            6 = "5.00";
            7 = "YRD.DO\U00c7.DR.AY\U015eEN TULPAR";
            8 = TeacherHold;
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 1;
            12 = "";
            2 = 1;
            3 = "CIP 101";
            4 = "Civic Involment Projects";
            5 = 0;
            6 = "1.00";
            7 = "YRD.DO\U00c7.DR.FATMA G\U00dcL AYGEN/Staff CIP1/SE\U00c7\U0130L AVCI/D\U0130LAYDA EM\U0130R/BA\U015eAK CANSU AK\U00c7EL\U0130K/\U00c7A\U011eLA UNGUN";
            8 = TeacherHold;
            9 = P;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 3;
            12 = "";
            2 = 1;
            3 = "COME 107";
            4 = "Algorithms and Programming I";
            5 = 4;
            6 = "5.00";
            7 = "PROF.DR.M\U0130TAT UYSAL";
            8 = TeacherHold;
            9 = "C+";
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 2;
            12 = "";
            2 = 1;
            3 = "ENG 101";
            4 = "Advanced English";
            5 = 2;
            6 = "3.00";
            7 = "OKT.EZG\U0130 ARGUN";
            8 = TeacherHold;
            9 = B;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 1;
            12 = "";
            2 = 1;
            3 = "IUL 100";
            4 = "Introduction to University Life";
            5 = 0;
            6 = "1.00";
            7 = "YRD.DO\U00c7.DR.FATMA G\U00dcL AYGEN";
            8 = TeacherHold;
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 2;
            12 = "";
            2 = 1;
            3 = "MATH 111";
            4 = "Calculus I";
            5 = 4;
            6 = "5.00";
            7 = "DO\U00c7.DR.G\U00dcRSEL YE\U015e\U0130LOT";
            8 = TeacherHold;
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 4;
            12 = "";
            2 = 1;
            3 = "PHYS 101";
            4 = "Physics I [CNE]";
            5 = 4;
            6 = "5.00";
            7 = "YRD.DO\U00c7.DR.AR\U0130F \U00d6ZBAY";
            8 = TeacherHold;
            9 = F;
        },
                {
            0 = "2013-2014";
            1 = "G\U00dcZ";
            10 = TeacherHold;
            11 = 9;
            12 = "";
            2 = 1;
            3 = "T\U00dcRK 101";
            4 = "T\U00fcrk Dili I [CNE]";
            5 = 2;
            6 = "2.00";
            7 = "\U00d6\U011eR.G\U00d6R.ARZU AYG\U00dcN";
            8 = TeacherHold;
            9 = F;
        }
    );
}
Bogdan
  • 1,286
  • 9
  • 12
  • [Here](http://example.com)'s the full swift file. I tried your code both before and after your edit but still it's not working. – Çağdaş Salur Jun 05 '14 at 17:37
  • It's fine for me. What exactly doesn't work? Button or downloading? Check your outlets. Does `println(tvNo.text + ":" + tvPw.text)` print what you need? – Bogdan Jun 05 '14 at 17:52
  • Yeah but i don't use them in the url for now anyway. Everything's working up until the line with `var jsonResult`. I can't find the error message too (i'm new to Xcode). You can check out the full [github project](https://github.com/cagdassalur/Dusor). – Çağdaş Salur Jun 05 '14 at 18:45
  • Can you look at the question: http://stackoverflow.com/questions/27478985/swift-dynamic-cast-failed-on-nsjsonserialization It throws an error of "Swift Dynamic Cast Failed" when I use your code. – tika Dec 15 '14 at 07:19
  • 1
    You should be using the NSURLConnectionDataDelegate protocol to implement these methods here...not NSURLConnectionDelegate – cspam Dec 29 '14 at 14:38
  • Also in the connection method you should use NSMutableData instead of NSData or you will get an error.(NSData does not have a member 'appendData') – cspam Dec 29 '14 at 18:56
  • And how do I "println()" just selected items, like for that example answer, all number "4"? – Marco Almeida Jan 17 '15 at 04:25
7

If the original JSON is an array, try this.

func parseJSON(inputData: NSData) -> Array<NSDictionary>{
    var error: NSError?
    var boardsDictionary = NSJSONSerialization.JSONObjectWithData(inputData, options: NSJSONReadingOptions.MutableContainers, error: &error) as Array<NSDictionary>

    return boardsDictionary
}
benka
  • 4,732
  • 35
  • 47
  • 58
colasking
  • 71
  • 1
4

The example below sends a request to fetch stock information - it's a bit more comprehensive, but has more cleanup and structure:

import Foundation

private let kSNStockInfoFetchRequestPath:String = "http://dev.markitondemand.com/Api/v2/Quote/json"

private func SNStockInfoFetchRequestURL(symbol:String) -> NSURL? {
  if let components:NSURLComponents = NSURLComponents(string:kSNStockInfoFetchRequestPath) {
    components.queryItems = [NSURLQueryItem(name:"symbol", value:symbol)]
    return components.URL
  }
  return nil
}

private func SNStockInfoFetchRequestURLRequest(symbol:String) ->  NSURLRequest? {
  if let requestURL:NSURL = SNStockInfoFetchRequestURL(symbol) {
    var request:NSMutableURLRequest = NSMutableURLRequest(URL:requestURL)
    request.HTTPMethod = "GET"
    return request
  }
  return nil
}

private func SNStockInfoFetchRequestParseData(receivedData:NSData, error:NSErrorPointer) -> NSDictionary? {
  return NSJSONSerialization.JSONObjectWithData(receivedData, options:NSJSONReadingOptions.MutableContainers, error:error) as? NSDictionary
}

class SNStockInfoFetchRequest: NSObject,
NSURLConnectionDataDelegate
{
  private let symbol:String
  private (set) var fetching:Bool
  private lazy var receivedData = NSMutableData()

  init(symbol:String) {
    self.symbol = symbol
    self.fetching = false
  }

  func start() {
    assert(!fetching, "Should not start a request that has already started!")
    fetching = true
    if let request:NSURLRequest = SNStockInfoFetchRequestURLRequest(symbol) {
      var connection:NSURLConnection = NSURLConnection(request:request, delegate:self, startImmediately:true)!
      connection.start()
    }
  }

  // MARK: NSURLConnectionDataDelegate

  func connection(connection:NSURLConnection, didReceiveData data:NSData) {
    assert(fetching, "Should only receive data while activly fetching!")
    self.receivedData.appendData(data)
  }

  func connectionDidFinishLoading(connection:NSURLConnection) {
    var error:NSError?
    if let result:NSDictionary = SNStockInfoFetchRequestParseData(receivedData, &error) {
      println(result)
    } else {
      println(error)
    }

  }
}

We can now use the request as such:

let fetcher:SNStockInfoFetchRequest = SNStockInfoFetchRequest(symbol:"MSFT")
fetcher.start()

This should output the JSON in case of a success, or the error in case of a failure. Hope this helps! If you use the same structure, make sure to use a delegate to either return the parsed JSON (or even better, an immutable value object) or indicate a failure.

Zorayr
  • 23,770
  • 8
  • 136
  • 129
3

The answer of @david72 worked perfectly for me. So here's the same in Swift 3 and URLSession for your convenience. Also with some added error printing for easier debugging.

func getHttpData(urlAddress : String)
{
    // Asynchronous Http call to your api url, using NSURLSession:
    guard let url = URL(string: urlAddress) else
    {
        print("Url conversion issue.")
        return
    }
    URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in
        // Check if data was received successfully
        if error == nil && data != nil {
            do {
                // Convert NSData to Dictionary where keys are of type String, and values are of any type
                let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:AnyObject]
                print(json)
                // Access specific key with value of type String
                // let str = json["key"] as! String
            } catch {
                print(error)
                // Something went wrong
            }
        }
        else if error != nil
        {
            print(error)
        }
    }).resume()
}
OwlOCR
  • 1,127
  • 11
  • 22
  • It's wise to escape your string: `let urlAddressEscaped = urlAddress.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)` and then use this escaped string to convert to url. – lenooh Nov 03 '16 at 23:39
2
//
//  ViewController.swift
//  Test2
//
//  Created by fingent on 11/08/15.
//  Copyright (c) 2015 fingent. All rights reserved.
//

import UIKit

class ViewController: UIViewController,NSURLConnectionDelegate

{
lazy var data = NSMutableData()

    @IBAction func t1(sender: AnyObject) {
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        startConnection()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func startConnection(){
        let urlPath: String = "https://api.github.com/users/mralexgray"
        var url: NSURL = NSURL(string: urlPath)!
        var request: NSURLRequest = NSURLRequest(URL: url)
        var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
        connection.start()
    }

    func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
        self.data.appendData(data)
    }

    func buttonAction(sender: UIButton!){
        startConnection()
    }

    func connectionDidFinishLoading(connection: NSURLConnection!) {
        var err: NSError
        // throwing an error on the line below (can't figure out where the error message is)
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        println(jsonResult)
    }


}
Alvin George
  • 14,148
  • 92
  • 64
2

Here is swift 3.1 code

URLSession.shared.dataTask(with: NSURL(string: "http://pastebin.com/raw/wgkJgazE")! as URL, completionHandler: { (data, response, error) -> Void in
        // Check if data was received successfully
        if error == nil && data != nil {
            do {
                // Convert NSData to Dictionary where keys are of type String, and values are of any type
                let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:AnyObject]
                // Access specific key with value of type String
                let str = json["key"] as! String
            } catch {
                // Something went wrong
            }
        }
    }).resume()
-1

Request api REST-GET in iOS Swift

I present a very simple App where a rest service is consumed through the GET method and the information obtained is presented in our main view.

  • Note: This project is built with CocoaPods, for more information go to https://cocoapods.org.
  • PodFile structure:
# Uncomment the next line to define a global platform for your project
# platform :ios, '8.0'

target 'ExampleRestApi' do
  # Comment the next line if you don't want to use dynamic frameworks
  #use_frameworks!
  
  # Pods for ExampleRestApi
  use_modular_headers!
  pod 'Alamofire', '~> 5.0'
  pod 'AFNetworking', '~> 2.6'
  pod 'ORStackView', '~> 3.0'

end

Steps

  • HelperNetwork.swift: Copy HelperNetwork file, which contains the method to consume the service through Alamofire.
//
//  HelperNetwork.swift
//  ExampleRestApi
//
//  Created by MacBook Pro on 20/11/20.
//

import Foundation
import Alamofire

public var  URL_API = "https://icenparty.pythonanywhere.com/icenPartyWeb/api/v1/"
public var  GET_STORE = "doStore"
public var  METHOD_GET: HTTPMethod = .get

class HelperNetwork{
    
    //Example get json for method GET
    func doRequest(urlString : String,
                   parameters : Parameters,
                   method : HTTPMethod,
                   completion: @escaping (AFDataResponse <Any>)->()) {
        
        let url = URL.init(string: URL_API + urlString)
        AF.request(url!, method: method, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON {
            response in  completion(response)
        }
    }
    
}
  • BaseResponse.swift: Copy BaseResponse file, which contains the models corresponding to the information obtained in the service response.
//
//  BaseResponse.swift
//  ExampleRestApi
//
//  Created by MacBook Pro on 20/11/20.
//
/*
 BaseResponse is used to create all the models that
 we need for the service response.
 */

import Foundation

public struct Store : Codable{
    var pk: Int
    var fields: Fields
}

public struct Fields : Codable {
    var file_img_home: String
    var file_img_2: String
    var file_img_3: String
    var title: String
    var subTitle: String
    var description: String
    var value: Int
    var material: String
    var color: String
    var sizes_list: String
    var brand: String
}

public struct JSONResponseStore: Codable {
    var success:  Bool
    var message:  String
    var stores :  [Store]
}
  • ViewController.swift: In our viewController file, call our doRequest method to which the necessary parameters are passed to obtain the json.
@IBOutlet weak var lblResponse: UILabel!
var helperNetwork = HelperNetwork()
    
/**
     Get info from server for method GET
     */
    func getJsonRequestGET(){
        
        //Set text lbl
        lblResponse.text = "Consultando información...."
        
        //parameters for get , we need tag typeStore
        let parameters: Parameters = [ "typeStore" : "Hombre",]
        
        self.helperNetwork.doRequest(urlString: GET_STORE,
                                     parameters: parameters,
                                     method: METHOD_GET) { (response) -> () in
            // do stuff with the result
            switch response.result
            {
            case .success( _):
                do {
                    
                    //Decode data From model JSONResponseStore , can be changed to any model
                    let JSONData = try JSONDecoder().decode(JSONResponseStore.self, from: response.data!)
                    
                    if(JSONData.success){
                        self.lblResponse.text = "Respuesta: \(JSONData.stores)"
                    }else{
                        self.lblResponse.text = "Respuesta: \(JSONData.message)"
                    }
                    
                } catch let jsonError {
                    self.lblResponse.text = "Respuesta: \(jsonError)"
                }
                
            case .failure(let error):
                self.lblResponse.text = "Respuesta: \(error)"
            }
        }
        
    }

I remain attentive to any concerns, Cheers

  • 1
    As you may have noticed, this site is in English. Don't assume others speak Spanish, and provide your answer in English. – tomfrio Nov 20 '20 at 20:39