0

Im a just starting with programming apps in Xcode 7 / Swift 2.0 Im am pretty far with developing my ideas, but I can't seem to get the error handling to work. The viewcontroller it concerns is presenting dates where and when our band plays.

In this Viewcontroller I call Json data from our online server and parse it into a tableview. It all works. But i want the following things to happen too.

  1. If there is no connection whatsoever (wifi/4G/3G) perform a segue (No Connection)
  2. If the server or the php script is unreachable, perform a segue (server error )
  3. If there is no data available (as in Empty Array) Just give a message "There are no dates set."

The Json I get from my PHP script:

(
        {
        date = "some date";
        description = "Some description";
        location = "Some location";
        others = "some details";
        showtime = "some time";
    },
        {
        date = "some date";
        description = "Some description";
        location = "Some location";
        others = "some details";
        showtime = "some time";
    }
)

This is the ViewController

import UIKit

class GigsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    var gigsdata: NSArray = []

    override func viewDidLoad() {
        super.viewDidLoad()

        let logo = UIImage(named: "where_is_header_navigationController.jpg")
        let imageView = UIImageView(image:logo)
        self.navigationItem.titleView = imageView

        func dataOfJson(url: String) -> NSArray {
            let gigsdata = NSData(contentsOfURL: NSURL(string: url)!)
            let jsonArray: NSArray = try! NSJSONSerialization.JSONObjectWithData(gigsdata!, options: .MutableContainers) as! NSArray
            return jsonArray
        }
        gigsdata = dataOfJson("http://www.mydomain.eu/app/myscript.php")

    }// end of viewDidLoad

    // MARK: Table View Delegate Methods
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        if gigsdata.count != 0 {
            return gigsdata.count

        } else {

            return 1
        }

    }

    func allowMultipleLines(tableViewCell:UITableViewCell) {
        tableViewCell.textLabel?.numberOfLines = 0
        tableViewCell.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("GigsCell")! as UITableViewCell
        // setting the text color
        cell.textLabel?.textColor = UIColor.whiteColor()
        //Getting the JSON data and turn it into objects
        let maingigsdata = (gigsdata[indexPath.row] as! NSDictionary)
        //setting constants for the detailview
        let gigsDate = maingigsdata["date"] as! String
        let gigsLocation = maingigsdata["location"] as! String
        // Setting the number of lines per row
        cell.textLabel!.numberOfLines = 2
        // Filling the cell with data
        cell.textLabel!.text = ("\(gigsDate) \n\(gigsLocation)")
        // setting the beackground color when selected
        let backgroundView = UIView()
        backgroundView.backgroundColor = UIColor.darkGrayColor()
        cell.selectedBackgroundView = backgroundView

        return cell
    }


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


}

Like i said, im fairly new to this, so please dont go around and name all kinds of proceduresm, functions or things like that. Please don't think that I don't try myself, but 'm stuck now for two weeks.

The thing I saw a lot on videos and tutorials was the DO TRY CATCH thing. But implementing that as good as I can gave me just all kinds of errors, so I must be doing something wrong there.

I hope that there is someone out there who can help me out and make me a lot wiser as I am today!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Johan
  • 1
  • 1

2 Answers2

0

You should use NSURLRequest or some lib like Alamofire to fetch the data. NSData contentsOfURL is not asynchronous and in your case blocks the main thread. I wonder if you can compile your code as NSData contentOfURL throws and exception, which must be catched. Check the domain of NSError object, which is thrown. It can be e.g. NSURLErrorDNSLookupFailed, NSURLErrorDomain, NSURLErrorNotConnectedToInternet, NSURLErrorInternationalRoamingOff.

https://github.com/Alamofire/Alamofire

To detech the connection type:

Detect carrier connection type (3G / EDGE / GPRS)

Example of the error handling based on your code:

do {
    // Blocks your UI if you do this in the main thread!
    let gigsdata = NSData(contentsOfURL: NSURL(string: url)!)
}
catch let error as! NSError {
    if error.domain == NSURLErrorNotConnectedToInternet {
        // If you do the data fetch using the background queue then this must be dispatched to the main queue:
        performSegueWithIdentifier("noInternet", sender: self)
    }
}
Community
  • 1
  • 1
Tapani
  • 3,191
  • 1
  • 25
  • 41
  • Thanks for your effort to help me. I previously used ALAMOFIRE, but it crashed when I tested it on my iphone. I will give it another try! – Johan Feb 08 '16 at 09:58
  • Now i've reinstalled Alamofire the proper way (through cocaopods) and also installed the swiftyJSON library and now it all works well, even on my iPhone. But the next task is rewriting all my code, but thats just a good practice :-) I'll keep you posted.... – Johan Feb 09 '16 at 18:06
0

For the 1st and 2nd issue I came up with the following working code:

// performing a first check if there is an connection based on the HTTPStatusCode 200
    Alamofire.request(.GET, "http://www.google.com")
        .responseJSON { response in
                      if response.response?.statusCode == 200 {
                      print("Code is 200 and good")
                        }else{
                        print("Code is not 200 and therefor bad")
                        self.performSegueWithIdentifier("NoConnectionSegue", sender: self)
                        }
                    }

I implemented the code in the first view controller of my app and the 'NoConnectionSegue' is a view controller that "blocks" the whole screen with a message that the app is not usable without an internet connection and a friendly request to close the app and try later. Of course the url "google.com" can be replaced with your own domain.

For the 3rd issue I had the following solution.

The viewcontroller is a TableView with cells populated by a json file on a remote server. At the end of the viewDidLoad I check if the array.count is less then 1. If so, then perform a segue to a new viewcontroller of the kind: "Present Modally" and the presentation: "Over current context". This way I don't get the navigationbar that I used in the previous Tableview. Leaving the original Tableview controller with one empty cell invisable in the background. It might not be the cleanest and the best way. But at least I got what I wanted.

the code:

// check if there are any gigs, otherwise perform segue to NoGigs
        if self.arrRes.count <= 1 {
            self.performSegueWithIdentifier("NoGigsSegue", sender: self)
        }
Johan
  • 1
  • 1