title: How to load data in viewDidLoad of DataViewController, without slowing down pageViewController scrolling?
body: <p>I have a dataViewController, which needs data from an API in order to populate a graph, and some news. The news API call is very fast and easy, but the graph call completely slows down the page scrolling as it is called in viewDidLoad(). I edited the graph API to download the data and then store it to cache, and instead on viewDidLoad, it checks if there is any data in cache, and then if there is some it uses that, but it is still terrible slow when scrolling pages. How can I fix this? Here is some of my DataViewController code that handles everything to do with the chart:</p>
  
  <pre><code>extension DataViewController {
  
  func GetOnlyDateMonthYearFromFullDate(currentDateFormate:NSString , conVertFormate:NSString , convertDate:NSString ) -&gt; NSString
  {
      let dateFormatter = DateFormatter()
      dateFormatter.dateFormat = currentDateFormate as String
      let formatter = DateFormatter()
      formatter.dateFormat = "yyyy'-'MM'-'dd'-'HH':'mm':'ssZZZ" as String
      let finalDate = formatter.date(from: convertDate as String)
      formatter.dateFormat = conVertFormate as String
      let dateString = formatter.string(from: finalDate!)
  
      return dateString as NSString
  }
  
  //Charts
  
  @objc func handleLongPress(longPressGesture:UILongPressGestureRecognizer) {
  
      let p = longPressGesture.location(in: self.chartView)
  
      if longPressGesture.state == UIGestureRecognizer.State.began &amp;&amp; isLineChartExpanded == false {
          mainLabelContainer.fadeOut()
          chartViewExpandedConstraints()
          isLineChartExpanded = true
  
          UIView.animate(withDuration: 0.5) {
              self.view.layoutIfNeeded()
          }
  
      } else if longPressGesture.state == UIGestureRecognizer.State.began &amp;&amp; isLineChartExpanded == true {
          mainLabelContainer.fadeIn()
          chartViewLandscapeConstraints()
          isLineChartExpanded = false
  
          UIView.animate(withDuration: 0.5) {
              self.view.layoutIfNeeded()
          }
      }
  
  }
  
  func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
      var xInt = Int()
      //The Currency Unit taken from the exchange section of the API.
  
      xInt = Int(entry.x)
      let currencyUnit = CGExchange.shared.exchangeData[0].rates[defaultCurrency]!.unit
  
      chartPriceLabel.textColor = UIColor.white.withAlphaComponent(0.5)
      chartDateLabel.textColor = UIColor.white.withAlphaComponent(0.5)
      chartPriceLabel.isHidden = false
      chartDateLabel.isHidden = false
      chartPriceLabel.text = "\(currencyUnit)\(round(1000*entry.y)/1000)"
  
      let date = self.GetOnlyDateMonthYearFromFullDate(currentDateFormate: "yyyy-MM-dd'T'HH:mm:ss.SSSZ", conVertFormate: "MMM d, h:mm a", convertDate: self.days[xInt] as NSString)
  
      chartDateLabel.text = "\(date as String)"
  }
  
  //Graph Buttons and states
  enum GraphStat {
      case day, fortnight, month
  }
  
  @objc func todayButtonAction(sender: UIButton!) {
  
          self.prices = []
          self.days = []
  
          CGCharts.shared.graphSetup = .day
          CGCharts.shared.getData(coin: self.dataObject, defaultCurrency: self.defaultCurrency, arr: true, completion: { (success) in
              self.prepareGraph(arr: true, completion: { (success) in
                  DispatchQueue.main.async {
                      self.chartView.animate(xAxisDuration: 4.0)
                  }
              })
          })
  
  }
  
  @objc func fortnightButtonAction(sender: UIButton!) {
  
          self.prices = []
          self.days = []
          CGCharts.shared.graphSetup = .week
          CGCharts.shared.getData(coin: self.dataObject, defaultCurrency: self.defaultCurrency, arr: true, completion: { (success) in
              self.prepareGraph(arr: true, completion: { (success) in
                  DispatchQueue.main.async {
                      self.chartView.animate(xAxisDuration: 4.0)
                  }
              })
          })
  
  }
  
  @objc func monthButtonAction(sender: UIButton!) {
  
          self.prices = []
          self.days = []
          CGCharts.shared.graphSetup = .month
          CGCharts.shared.getData(coin: self.dataObject, defaultCurrency: self.defaultCurrency, arr: true, completion: { (success) in
              self.prepareGraph(arr: true, completion: { (success) in
                  DispatchQueue.main.async {
                      self.chartView.animate(xAxisDuration: 4.0)
                  }
              })
  
          })
  
  }
  func lineChartUpdate(dataPoints: [String], values: [Double]) {
  
      if CGCharts.shared.graphSetup == .day {
          graphSetup = .day
      } else if CGCharts.shared.graphSetup == .week {
          graphSetup = .fortnight
      } else if CGCharts.shared.graphSetup == .month {
          graphSetup = .month
      }
  
      //Graph State buttons switch status for highlighting buttons.
      switch graphSetup {
  
      case .day:
          todayButton.alpha = 0.5
          fortnightButton.alpha = 1.0
          monthButton.alpha = 1.0
      case .fortnight:
          fortnightButton.alpha = 0.5
          todayButton.alpha = 1.0
          monthButton.alpha = 1.0
      case .month:
          monthButton.alpha = 0.5
          todayButton.alpha = 1.0
          fortnightButton.alpha = 1.0
      }
  
      //Graph data management
      var lineChartEntry = [ChartDataEntry]()
  
      for i in 0..&lt;prices.count {
  
          //Graph marker from extension
  
          if prices != [] {
  
              let value = ChartDataEntry(x: Double(i), y: values[i])
              lineChartEntry.append(value)
  
              let line1 = LineChartDataSet(values: lineChartEntry, label: "Price")
  
              let dateFormatter = DateFormatter()
              dateFormatter.dateStyle = .medium
              dateFormatter.timeStyle = .none
              dateFormatter.locale = Locale(identifier: "en_US")
  
              let dateObjects = self.days.compactMap { dateFormatter.date(from: $0) }
              let dateStrings = dateObjects.compactMap { dateFormatter.string(from: $0) }
  
              self.chartView.xAxis.valueFormatter = DefaultAxisValueFormatter(block: {(index, _) in
                  return dateStrings[Int(index)]
              })
  
              line1.setColor(.white)
              line1.drawVerticalHighlightIndicatorEnabled = true
              line1.drawHorizontalHighlightIndicatorEnabled = true
              line1.mode = .cubicBezier
              line1.lineWidth = 2.0
              line1.drawValuesEnabled = true
              line1.valueTextColor = UIColor.white
              line1.drawCirclesEnabled = false
  
              chartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:dateStrings)
              chartView.xAxis.granularity = 1
              chartView.leftAxis.drawGridLinesEnabled = false
              chartView.xAxis.drawGridLinesEnabled = false
              //Expanded
  
              chartView.rightAxis.enabled = false
              chartView.leftAxis.enabled = false
              chartView.xAxis.enabled = false
  
              chartView.rightAxis.drawGridLinesEnabled = false
              chartView.legend.enabled = false
  
              chartView.dragEnabled = false
              chartView.pinchZoomEnabled = false
              chartView.drawMarkers = false
              chartView.doubleTapToZoomEnabled = false
  
              chartView.isUserInteractionEnabled = true
  
              //Graph Data.
              let data = LineChartData()
              data.addDataSet(line1)
              chartView.data = data
  
          }
  
      }
  
  }
  
  //Dismiss Keyboard when Tap
  override func touchesBegan(_ touches: Set&lt;UITouch&gt;,
                             with event: UIEvent?) {
      self.view.endEditing(true)
  }
  //GraphData
  func prepareGraph(arr: Bool, completion: @escaping (Bool) -&gt; ()) {
      if Storage.fileExists("\(dataObject)GraphData", in: Storage.Directory.caches) {
          print("Exists")
          self.priceData = Storage.retrieve("\(dataObject)GraphData", from: Storage.Directory.caches, as: [Price].self)
          self.days = self.priceData.map({ $0.date.description })
          self.prices = self.priceData.map({ $0.price })
  
          DispatchQueue.main.async {
              //                self.chartView.animate(xAxisDuration: 4.0)
              self.lineChartUpdate(dataPoints: self.days, values: self.prices)
          }
  
      } else {
      self.prices = []
      self.days = []
  print("didn'tExist")
      CGCharts.shared.graphSetup = .day
  
              print("ChartsCleared")
              CGCharts.shared.getData(coin: self.dataObject, defaultCurrency: self.defaultCurrency, arr: true) { (success) in
                  self.updateGraph()
                  DispatchQueue.main.async {
                      self.lineChartUpdate(dataPoints: self.days, values: self.prices)
                  }
              }
      }
  }
  //GraphData In Storage
  func updateGraph() {
  
      self.priceData = Storage.retrieve("\(dataObject)GraphData", from: Storage.Directory.caches, as: [Price].self)
  
      self.days = self.priceData.map({ $0.date.description })
      self.prices = self.priceData.map({ $0.price })
  
          DispatchQueue.main.async {
              //                self.chartView.animate(xAxisDuration: 4.0)
              self.lineChartUpdate(dataPoints: self.days, values: self.prices)
          }
  
  }
  }
  </code></pre>
  
  <p>Here is the actual API call from the API manager file:</p>
  
  <pre><code>import Foundation
  
  
  struct Root: Codable {
  let prices: [Price]
  }
  struct Price: Codable {
  let date: Date
  let price: Double
  }
  
  class CGCharts {
  
  
  var priceData = [Price]()
  
  static let shared = CGCharts()
  
  var currency = ""
  var days = ""
  
  enum GraphStatus {
      case day, week, month
  }
  
  
  var graphSetup = GraphStatus.day
  
  func getAllCharts(arr: Bool, completion: @escaping (Bool) -&gt; ()) {
  
  }
  
  
  func getData(coin: String, defaultCurrency: String, arr: Bool, completion: @escaping (Bool) -&gt; ()) {
  
      switch graphSetup {
  
      case .day:
          days = "1"
      case .week:
          days = "14"
      case .month:
          days = "30"
  
      }
  
      let urlJSON = "https://api.coingecko.com/api/v3/coins/\(coin)/market_chart?vs_currency=\(defaultCurrency)&amp;days=\(days)"
  
      guard let url = URL(string: urlJSON) else { return }
  
      URLSession.shared.dataTask(with: url) { (data, response, err) in
  
          guard let data = data else { return }
  
          do {
              let prices = try JSONDecoder().decode(Root.self, from: data).prices
              print(prices.first!.date.description(with:.current))  // "Saturday, September 1, 2018 at 6:25:38 PM Brasilia Standard Time\n"
              print(prices[0].price)
              self.priceData = prices
  
              Storage.store(self.priceData, to: Storage.Directory.caches, as: "\(coin)GraphData")
  
  
              completion(arr)
  
          } catch {
              print(error)
          }
  
          }.resume()
  
  }
  
  }
  
  extension Price {
  public init(from decoder: Decoder) throws {
      var unkeyedContainer = try decoder.unkeyedContainer()
      let date = try unkeyedContainer.decode(UInt64.self).date
      let price = try unkeyedContainer.decode(Double.self)
      self.init(date: date, price: price)
  }
  public func encode(to encoder: Encoder) throws {
      var container = encoder.unkeyedContainer()
      try container.encode(date.unixEpochTime)
      try container.encode(price)
  }
  }
  
  extension UInt64 {
  var date: Date {
      return Date(timeIntervalSince1970: TimeInterval(self)/1000)
  }
  }
  extension Date {
  var unixEpochTime: UInt64 {
      return UInt64(timeIntervalSince1970*1000)
  }
  }
  </code></pre>
  
  <p>Something in one of these two files is just too slow, making page scrolling really annoying. It's only about 2 seconds, but it freezes the paging animation for that 2 seconds, I need to find a way to make scrolling smooth and responsive, even if it means not showing any chart data for a couple of seconds until it loads. How can I do this, and what is it exactly that is slowing everything down so much? I also have a suspition it could be to do with: </p>
  
  <pre><code>self.priceData = Storage.retrieve("\(dataObject)GraphData", from: Storage.Directory.caches, as: [Price].self)
          self.days = self.priceData.map({ $0.date.description })
          self.prices = self.priceData.map({ $0.price })
  </code></pre>
  
  <p>as this is looping through a big struct with the data and then adding them to 2 arrays, maybe that is holding everything up while it occurs? Thank you.</p>