Как загрузить данные в viewDidLoad DataViewController, не замедляя прокрутку pageViewController? - PullRequest
0 голосов
/ 22 октября 2018

У меня есть dataViewController, которому нужны данные из API для заполнения графика и некоторые новости.Вызов новостного API очень быстрый и простой, но вызов графа полностью замедляет прокрутку страницы, как это вызывается в viewDidLoad ().Я отредактировал API графика, чтобы загрузить данные и затем сохранить их в кеше, и вместо этого в viewDidLoad он проверяет, есть ли какие-либо данные в кеше, а затем, если они есть, использует их, но при прокрутке страниц он все еще ужасно медленный.,Как я могу это исправить?Вот мой код DataViewController, который обрабатывает все, что связано с диаграммой:

extension DataViewController {

func GetOnlyDateMonthYearFromFullDate(currentDateFormate:NSString , conVertFormate:NSString , convertDate:NSString ) -> 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 && isLineChartExpanded == false {
        mainLabelContainer.fadeOut()
        chartViewExpandedConstraints()
        isLineChartExpanded = true

        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }

    } else if longPressGesture.state == UIGestureRecognizer.State.began && 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..<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<UITouch>,
                           with event: UIEvent?) {
    self.view.endEditing(true)
}
//GraphData
func prepareGraph(arr: Bool, completion: @escaping (Bool) -> ()) {
    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)
        }

}
}

Вот фактический вызов API из файла менеджера API:

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) -> ()) {

}


func getData(coin: String, defaultCurrency: String, arr: Bool, completion: @escaping (Bool) -> ()) {

    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)&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)
}
}

Что-то в одном изэти два файла слишком медленные, что делает прокрутку страниц действительно раздражающей.Это всего лишь около 2 секунд, но он останавливает анимацию подкачки на эти 2 секунды, мне нужно найти способ сделать прокрутку плавной и отзывчивой, даже если это означает, что не показывать какие-либо данные графика в течение пары секунд, пока не загрузится.Как я могу это сделать, и что именно так сильно все тормозит?У меня также есть подозрение, что это может быть связано с:

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 })

, поскольку это перебирает большую структуру с данными и затем добавляет их в 2 массива, может быть, это удерживает все, пока это происходит?Спасибо.

1 Ответ

0 голосов
/ 24 октября 2018
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
  guard let self = self else {
    return
  }
  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 { [weak self] in
   // update your UI here based on the data
  }
}
...