0

I am having the problem in refreshing my JSON data through pull to refresh.When I launch my application, then it is displaying the data but when I pull to refresh then it is not refreshing. I have implemented the Refresh Control to refresh data. I am able to see the wheel icon of the pull to refresh, but it's not updating the JSON data.

Here is my code:

struct JSONData {
    let country: String
    let indicename: String
    let currPrice: String
    let chg: String
    let perChg: String

    init?(dictionary: [String:Any]) {
        guard let country = dictionary["Country"] as? String,
            let indicename = dictionary["Indicename"] as? String,
            let currPrice = dictionary["CurrPrice"] as? String,
            let chg = dictionary["Chg"] as? String,
            let perChg = dictionary["perChg"] as? String else {
                return nil
        }
        self.country = country
        self.indicename = indicename
        self.currPrice = currPrice
        self.chg = chg
        self.perChg = perChg
    }
}

       class SouthAViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,IndicatorInfoProvider {

    var datas = [JSONData]()
        var refreshControl = UIRefreshControl()

          @IBOutlet var tableview: UITableView!

        var arrowupimage : UIImage = UIImage(named : "arrowup")!
        var arrowdownimage : UIImage = UIImage(named : "arrowdown")!

        // I haven't shared the URL of parsing for security reasons

        let url=NSURL(string:"*******************************")
        let stringurl = "***************************"



        override func viewDidLoad() {
            super.viewDidLoad()

            if #available(iOS 10.0, *) {
                tableview.refreshControl = refreshControl
            } else {
                tableview.addSubview(refreshControl)
            }

            self.refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")

            self.refreshControl.addTarget(self, action: #selector(SouthAViewController.refresh), for: UIControlEvents.valueChanged)


            navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
            self.downloadJsonWithURL()
            tableview.delegate = self
            tableview.dataSource = self
        }

        func refresh(){
            self.downloadJsonWithURL()

        }

        // downloading JSON data to display on this class

        func downloadJsonWithURL() {

             let task = URLSession.shared.dataTask(with: URL(string: stringurl)!) { (data, response, error) in
            if error != nil {
              //  print(error?.localizedDescription)
                return
            }
            if let contdata = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [String:Any] {

                if let arrJSON = contdata["data"] as? [[String:Any]] {
                    self.datas = arrJSON.flatMap(JSONData.init)

                        //Reload tableView and endRefreshing the refresh control
                        DispatchQueue.main.async {
                        self.tableview.reloadData()
                        self.refreshControl.endRefreshing()
                        }
                }
            }
        }
        task.resume()

        }

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



        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

            return datas.count
        }

        //setting data on the table view cell

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "southacell", for: indexPath) as! southacell


        cell.Indicename?.text = datas[indexPath.row].indicename
        cell.Country?.text = datas[indexPath.row].country
        cell.CurrPrice?.text = datas[indexPath.row].currPrice


            return cell
        }

    }

json sample :

{  "data":[  
      {  
         "Country":"China",
         "Indicename":"SZSE COMPONENT INDEX",
         "date":"2017-06-23 14:53:57",
         "zone":"GMT+8",
         "CurrPrice":"10355.3",
         "Chg":"90.07",
         "PerChg":"0.88",
         "prev_close":"10265.2"
      },
      {  
         "Country":"China",
         "Indicename":"Shanghai Composite",
         "date":"2017-06-23 14:52:54",
         "zone":"GMT+8",
         "CurrPrice":"3155.9",
         "Chg":"8.44",
         "PerChg":"0.27",
         "prev_close":"3147.45"
      }
]
}
Samarth Kejriwal
  • 1,168
  • 2
  • 15
  • 30
  • the data is returned from server on refresh time – Anbu.Karthik Jun 23 '17 at 05:53
  • I dont think, if it would have happened then it would have been updated also. – Samarth Kejriwal Jun 23 '17 at 05:55
  • The first time when i run my application then the data is being loaded in my table view cell – Samarth Kejriwal Jun 23 '17 at 05:55
  • chekc once .... – Anbu.Karthik Jun 23 '17 at 05:58
  • should i print the value in my refresh function and them check ?? – Samarth Kejriwal Jun 23 '17 at 06:00
  • @SamarthKejriwal Is it loading data in tableView when you load the screen ? If yes edit your question with current code that you are trying also put once break point and check reload data in completion block is executing or not – Nirav D Jun 23 '17 at 06:27
  • @NiravD I have updated the code, am I loading the data correctly in table view cell ,please check it sir – Samarth Kejriwal Jun 23 '17 at 06:42
  • @NiravD No I am not getting any data right now through the above code when I am loading my app. Now no data is being displayed. and while putting the breakpoint I saw that the `datas` array is not getting any value from json – Samarth Kejriwal Jun 23 '17 at 06:52
  • @NiravD i have added the json sample – Samarth Kejriwal Jun 23 '17 at 06:57
  • 1
    @SamarthKejriwal The issue is to small, change single line in `init` of JSONData `let perChg = dictionary["PerChg"] as? String else {` for key `PerChg` `P` is capital currently it is in lowercase make it capital and you all good to go. – Nirav D Jun 23 '17 at 07:02
  • @NiravD ok sir i did it . But what about the refresh .It is stiill not working – Samarth Kejriwal Jun 23 '17 at 07:08
  • 1
    @SamarthKejriwal Is refresh control showing when you refresh the tableView ? Also put break point inside `refresh` and check it is getting called or not ? – Nirav D Jun 23 '17 at 07:11
  • @NiravD yes sir refresh function is being called.But it is not refreshing the data – Samarth Kejriwal Jun 23 '17 at 07:24
  • @SamarthKejriwal Check this line `self.datas = arrJSON.flatMap(JSONData.init)` is executing when you refresh the tableView put break point and check it. if it is executing that means you are getting the same data so tableView is showing the same result. – Nirav D Jun 23 '17 at 07:26
  • @NiravD Sir its done. Now it's refresing the data – Samarth Kejriwal Jun 23 '17 at 07:26
  • @NiravD thanks a lot, sir. You helped me a lot with this. May I get your email id to get in contact in case of any problem. I am just a beginner right now in IOS – Samarth Kejriwal Jun 23 '17 at 07:29
  • @SamarthKejriwal You can ping me here on this question, with your new question link If I have solution will post on you question. – Nirav D Jun 23 '17 at 07:30
  • @NiravD great sir. Thanks :) – Samarth Kejriwal Jun 23 '17 at 07:31
  • @NiravD I posted a question yesterday regarding the ios charts .Please do have a look at it and provide any solution if u have. https://stackoverflow.com/questions/44700493/how-to-set-space-between-x-axis-labels-in-ios-charts – Samarth Kejriwal Jun 23 '17 at 08:50
  • @SamarthKejriwal I have already seen this question, I haven't work with charts so don't have any solution for tha. – Nirav D Jun 23 '17 at 08:53
  • 1
    @NiravD Okk Sir ! – Samarth Kejriwal Jun 23 '17 at 08:55
  • @NiravD Sir I am facing a problem in setting the dynamic resizing of table view cell. I tried this in my `viewDidLoad()` method : `tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 120` and in my storyboard also I have set the custom row height as 120, but it's not working.It is in fact now displaying a bigger cell height than before .What may be the reason? Should I post a question for it or you have an answer? – Samarth Kejriwal Jun 26 '17 at 05:34
  • @SamarthKejriwal The issue may related to constraints add new question with your cell's content with its constraints – Nirav D Jun 26 '17 at 05:36
  • @NiravD how should i show you the constraints. I have added them in the storyboard – Samarth Kejriwal Jun 26 '17 at 05:46
  • @SamarthKejriwal Actually currently I'm busy with some task so will not able to help you now, so better if you add new question – Nirav D Jun 26 '17 at 05:47
  • 1
    @NiravD okk sir . I . will send you the link over here.Please do have a look when u get time – Samarth Kejriwal Jun 26 '17 at 05:53
  • @NiravD sir whenever you get time.please check this out : https://stackoverflow.com/questions/44753952/not-able-to-set-the-dynamic-height-of-table-view-cell – Samarth Kejriwal Jun 26 '17 at 06:16
  • @NiravD Sir i am in a problem ,sir now my whole project seems to be absurdly aligned , i was going through a tutorial and i disable Auto Layout in File inspector and now my whole project is messed up i think , is there any solution to get things back done in the same layout or i have to assign the constraint again ? – Samarth Kejriwal Jun 26 '17 at 09:31
  • @SamarthKejriwal Don't get you. – Nirav D Jun 26 '17 at 11:24
  • @NiravD leave it sir , the main issue is i am not able to set the constraints for all the labels and other content of my table view cell for setting it to have dynamic height – Samarth Kejriwal Jun 26 '17 at 11:38
  • I want to set the dynamic height so the main issue is my contraints . Thats why i am having trouble, it's a bit confusing – Samarth Kejriwal Jun 26 '17 at 11:41
  • @NiravD I solved the issue sir :) – Samarth Kejriwal Jun 26 '17 at 12:38
  • @SamarthKejriwal Thats great that you made it :) – Nirav D Jun 26 '17 at 12:39
  • @NiravD Sir how do we convert a particular date into UTC. I used the following code: `let formatter1 = DateFormatter() formatter1.dateFormat = "yyyy-MM-dd HH:mm:ss" formatter1.timeZone = TimeZone(abbreviation: "UTC") let parsed = formatter1.date(from: self.datas[0].date)` It is showing me the following result : 2017-06-27 18:05:01 +0000 Is it the correct time being displayed? – Samarth Kejriwal Jun 27 '17 at 17:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/147781/discussion-between-nirav-d-and-samarth-kejriwal). – Nirav D Jun 28 '17 at 06:27
  • @NiravD Sir I have made my whole view with all the labels and images done , but now I want to make the whole view scrollable by adding a scroll view ,is it possible to add the scroll view at the bottom of the whole view without disturbing the layouts of the labels and images – Samarth Kejriwal Jun 30 '17 at 11:36

2 Answers2

1

Don't use Data(contentsOf:) to retrieve data from URL what you need to use is URLSession with datatask to retrieve data from URL after that you need to reload the tableView and ending animation of RefreshControl inside the completion block of datatask(with:). Also instead of handling multiple array what you need to do is create one array of custom class or struct

struct Data {
    var country: String
    var indicename: String
    var currPrice: String
    var chg: String
    var perChg: String

    init?(dictionary: [String:Any]) {
        guard let country = dictionary["Country"] as? String,
              let indicename = dictionary["Indicename"] as? String,
              let currPrice = dictionary["CurrPrice"] as? String,
              let chg = dictionary["Chg"] as? String,
              let perChg = dictionary["PerChg"] as? String else {
            return nil
        }
        self.country = country
        self.indicename = indicename
        self.currPrice = currPrice
        self.chg = chg
        self.perChg = perChg
    }
}

Now declare simply one array of type [Data] and use this will your tableView methods.

var datas = [Data]()

Now simply use this single array to store all the data and display data in tableView.

func refresh(){
    self.downloadJsonWithURL()
}

func downloadJsonWithURL() {
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print(error?.localizedDescription)
            return
        }
        if let contdata = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [String:Any] {
            if let arrJSON = contdata["data"] as? [[String:Any]] {
                self.datas = arrJSON.flatMap(Data.init)
                //Reload tableView and endRefreshing the refresh control 
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                    self.refreshControl.endRefreshing()
                }
            }
        }
    }
    task.resume()
}

//tableView methods

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return data.count
}

//setting data on the table view cell

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "southacell", for: indexPath) as! southacell


    let curpricefloat : Double = Double(datas[indexPath.row].currPrice)!
    let Chgfloat : Double = Double(datas[indexPath.row].chg)!
    let perchgfloat : Double = Double(datas[indexPath.row].perChg)!

    cell.Indicename?.text = datas[indexPath.row].indicename
    cell.Indicename.font = UIFont.boldSystemFont(ofSize: 19.0)
    cell.Country?.text = datas[indexPath.row].country

    cell.PerChg?.text = "(" + String(format: "%.2f", perchgfloat) + "%)"
    cell.CurrPrice?.text = String(format: "%.2f", curpricefloat)
    cell.Chg?.text = String(format: "%.2f", Chgfloat)

    if Float((cell.Chg?.text)!)! < 0 {

        datas[indexPath.row].chg = datas[indexPath.row].chg.replacingOccurrences(of: "-", with: "")
        datas[indexPath.row].perChg = datas[indexPath.row].perChg.replacingOccurrences(of: "-", with: "")

        cell.PerChg?.text = "(" + datas[indexPath.row].perChg + "%)"
        cell.Chg?.text = datas[indexPath.row].chg

        cell.Chg?.textColor = UIColor.red
        cell.PerChg?.textColor = UIColor.red
        cell.arrow?.image = UIImage(named : "arrowdown")

    } else
    {
        cell.Chg?.textColor = UIColor.green
        cell.PerChg?.textColor = UIColor.green
        cell.arrow?.image = UIImage(named : "arrowup")
    }

    if cell.Country!.text! == "Argentina"{
        cell.countryFlag?.image = UIImage(named : "argentina")
    }
    else if cell.Country!.text! == "Brazil"{
        cell.countryFlag?.image = UIImage(named : "brazil")
    }
    else if cell.Country!.text! == "Peru"{
        cell.countryFlag?.image = UIImage(named : "peru")
    }
    else{
        cell.countryFlag?.image = UIImage(named : "unknown")
    }

    return cell
}
Nirav D
  • 71,513
  • 12
  • 161
  • 183
0

Try the following:

override func viewDidLoad() {
    super.viewDidLoad()

    // MARK: Refresh control
    updateData.backgroundColor = .black
    updateData.tintColor = .white
    updateData.attributedTitle = NSAttributedString(string: "Updating Tap 
List...", attributes: [NSForegroundColorAttributeName: UIColor(red: 
255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1.0)])
    updateData.addTarget(self, action: 
#selector(ViewController.loadNewData), for: UIControlEvents.valueChanged)
    tapListTableView.addSubview(updateData)
    tapListTableView.sendSubview(toBack: updateData)

        DispatchQueue.main.async {
            self.tableview.reloadData()
        }
    }
}