简体   繁体   English

Swift:如何刷新表格视图而不会出现滞后(UIRefreshControl)

[英]Swift: How to refresh tableview without lag (UIRefreshControl)

Filling my table view with objects from a MYSQL database using PHP and JSON to Swift 3. I have a pull down to refresh function but when I'm pulling down to refresh it lags mid way for a second and then continues (like the wheel won't spin for a second). 使用PHP和JSON从Swift到MYSQL数据库中的对象填充表视图到Swift3。我有一个下拉刷新功能,但是当我下拉刷新时,它会滞后一秒钟,然后继续执行(就像滚轮一样)不会旋转一秒钟)。

How can I update my tableview smoother because I'm guessing as I add more content to the database in the future the bigger the lag. 我如何才能更平滑地更新tableview,因为我猜测随着日后向数据库中添加更多内容的滞后时间变大。 I currently have 12 objects in my database so imagine with 100+ objects. 我的数据库中目前有12个对象,因此可以想象有100多个对象。

In viewDidLoad 在viewDidLoad中

// Pull to Refresh
    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    if #available(iOS 10.0, *) {
        myTableView.refreshControl = refreshControl
        print("iOS 10")
    } else {
        myTableView.addSubview(refreshControl)
        print("iOS 9 or iOS 8")
    }

Then pull to refresh function 然后拉刷新功能

// Pull to Refresh
func handleRefresh(refreshControl: UIRefreshControl) {

    // Fetching Data for TableView
    retrieveDataFromServer()

    // Stop Refreshing
    refreshControl.endRefreshing()
}

// Retrieving Data from Server
func retrieveDataFromServer() {

    // Loading Data from File Manager
    loadData()

    let getDataURL = "http://example.com/receiving.php"
    let url: NSURL = NSURL(string: getDataURL)!

    do {
        let data: Data = try Data(contentsOf: url as URL)
        let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray

        // Clear the arrays
        self.followedArray = [Blog]()
        self.mainArray = [Blog]()

        // Looping through jsonArray
        for jsonObject in jsonArray {

            if let blog = Blog(jsonObject:jsonObject as! [String : Any]) {

                // Check if Identifiers Match
                if followedIdentifiers.contains(blog.blogID) {
                    self.followedArray.append(blog)
                } else {
                    self.mainArray.append(blog)
                }
            }
        }
    } catch {
        print("Error: (Retrieving Data)")
    }
    myTableView.reloadData()
}

Refer to the apple sample code at the following location: 请参阅以下位置的苹果示例代码:

http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html

Couple of suggestion : 几个建议:

Don't show the data at cellForRowAtIndexPath: method 'cause at this time cell is not displayed yet. 不要在cellForRowAtIndexPath处显示数据:方法“因为此时尚未显示单元格。 Try to use tableView:willDisplayCell:forRowAtIndexPath: method in the delegate of UITableView. 尝试在UITableView的委托中使用tableView:willDisplayCell:forRowAtIndexPath:方法。

Re-Use single instance of cell/header/footer even if you need to show more. 重新使用单元格/页眉/页脚的单个实例,即使您需要显示更多。

Let me know if anything specific is needed. 让我知道是否需要任何具体说明。

    Spinner.isHidden = false
    Spinner.startAnimating()
    DispatchQueue.global(qos: .background).async {
       loadData()

    let getDataURL = "http://example.com/receiving.php"
    let url: NSURL = NSURL(string: getDataURL)!

    do {
        let data: Data = try Data(contentsOf: url as URL)
        let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray

        // Clear the arrays
        self.followedArray = [Blog]()
        self.mainArray = [Blog]()

        // Looping through jsonArray
        for jsonObject in jsonArray {

            if let blog = Blog(jsonObject:jsonObject as! [String : Any]) {

                // Check if Identifiers Match
                if followedIdentifiers.contains(blog.blogID) {
                    self.followedArray.append(blog)
                } else {
                    self.mainArray.append(blog)
                }
            }
        }
    } catch {
        print("Error: (Retrieving Data)")
    }

        DispatchQueue.main.async
        {

            myTableView.reloadData()
            self.Spinner.startAnimating()
            self.Spinner.isHidden = true
        }
    }

My guess is that your retrieveDataFromServer() is blocking the main thread, and therefore causing the lag. 我的猜测是您的retrieveDataFromServer()阻塞了主线程,因此导致了延迟。 Try wrapping it in an async block 尝试将其包装在异步块中

// Pull to Refresh
func handleRefresh(refreshControl: UIRefreshControl) {

    // Fetching Data for TableView
    retrieveDataFromServer { [weak refreshControl] in
        // This block will run once retrieveDataFromServer() is completed

        // Reload data
        myTableView.reloadData()

        // Stop Refreshing
        refreshControl?.endRefreshing()
    }
}

// Retrieving Data from Server
func retrieveDataFromServer(completion: (() -> Void)?) {

    // Loading Data from File Manager
    loadData()

    let getDataURL = "http://example.com/receiving.php"
    let url: NSURL = NSURL(string: getDataURL)!

    do {
        let data: Data = try Data(contentsOf: url as URL)
        let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray

        // Clear the arrays
        self.followedArray = [Blog]()
        self.mainArray = [Blog]()

        // Looping through jsonArray
        for jsonObject in jsonArray {

            if let blog = Blog(jsonObject:jsonObject as! [String : Any]) {

                // Check if Identifiers Match
                if followedIdentifiers.contains(blog.blogID) {
                    self.followedArray.append(blog)
                } else {
                    self.mainArray.append(blog)
                }
            }
        }
    } catch {
        print("Error: (Retrieving Data)")
    }

    // Calls completion block when finished
    completion?()
}

I imagine the lag you're experiencing is due to the network request being executed synchronously on the main thread: 我想象您遇到的滞后是由于网络请求在主线程上同步执行:

let data: Data = try Data(contentsOf: url as URL)

Network requests are slow and should almost certainly be done off the main thread. 网络请求很慢,几乎可以肯定应该在主线程之外完成。 The solution here is to move the networking call to a background thread so the main (UI) thread doesn't get blocked (lag). 此处的解决方案是将网络调用移至后台线程,以使主(UI)线程不会被阻塞(滞后)。

So how do you do that? 那你怎么做呢? Well that is a large question with many different answers. 嗯,这是一个很大的问题,有许多不同的答案。

I highly recommend you spend some time learning about multi-threaded programming (also known as concurrency) in Swift. 我强烈建议您花一些时间来学习Swift中的多线程编程(也称为并发)。 Going through this Ray Wenderlich tutorial should give you a good foundation. 通过本Ray Wenderlich教程应该会为您奠定良好的基础。

Then it's probably a good idea to learn about URLSession which is used for performing asynchronous network requests in iOS apps. 那么了解URLSession可能是一个好主意,URLSession用于在iOS应用中执行异步网络请求。 Again Ray Wenderlich has a great starter tutorial . 雷·温德利奇(Ray Wenderlich)再次提供了很棒的入门教程

Finally... here is a quick and dirty solution for you. 最后...这是为您准备的快速而肮脏的解决方案。 It's "hacky" and you probably shouldn't use it, but it will probably fix your lag issue: 它是“ hacky”的,您可能不应该使用它,但是它可能会解决滞后问题:

func retrieveDataFromServer() {

    // Loading Data from File Manager
    loadData()

    let getDataURL = "http://example.com/receiving.php"
    let url: NSURL = NSURL(string: getDataURL)!

    // Move to a background queue to fetch and process data from network.
    DispatchQueue.global().async {

        // Don't touch anything related to the UI here.
        do {
            let data: Data = try Data(contentsOf: url as URL)
            let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray

            // Create new temp arrays to process json
            var tempFollowedArray = [Blog]()
            var tempMainArray = [Blog]()

            // Looping through jsonArray
            for jsonObject in jsonArray {

                if let blog = Blog(jsonObject:jsonObject as! [String : Any]) {

                    // Check if Identifiers Match
                    if self.followedIdentifiers.contains(blog.blogID) {
                        tempFollowedArray.append(blog)
                    } else {
                        tempMainArray.append(blog)
                    }
                }
            }

            // Jump back to main (UI) thread to update results
            DispatchQueue.main.async {
                print("success")
                self.followedArray = tempFollowedArray
                self.mainArray = tempMainArray

                self.myTableView.reloadData()
            }
        } catch {
            DispatchQueue.main.async {
                print("Error: (Retrieving Data)")
                // This reload is probably not necessary, but it was
                // in your original code so I included it.
                self.myTableView.reloadData()
            }
        }
    }
}

Try this: 尝试这个:

@objc func handleRefresh(_ refreshControl: UIRefreshControl) {

    refreshControl.endRefreshing()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    retrieveDataFromServer()
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM