使用YouTube api在UITableViewCell中加载nextPageToken是否缓慢且滞后?

时间:2016-02-14 23:56:33

标签: ios swift uitableview youtube-api

在使用youtube api加载我的UITableViewCell中的nextPageToken时,我遇到了一些问题。

加载视图时,单元格会加载默认的5个播放列表,缩略图和播放列表的标题,如下所示:

enter image description here

当用户向下滚动,并且通过nextPageToken获取更多数据时,单元格开始滞后。

如何解决此问题?如何像YouTube应用程序一样顺利加载下一个令牌?

这是我的代码:

var playlistItems: [AnyObject] = []

override func viewDidLoad()
{
    getChannelDetails("https://www.googleapis.com/youtube/v3/playlists?part=contentDetails,snippet&channelId=UCJKOvdk-nVzDAFR_9MF64sw&key=\(apiKey)")
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{        
    return playlistItems.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    var cell: UITableViewCell!

    // Dequeue the cell to load data
    cell = tableView.dequeueReusableCellWithIdentifier("Playlist", forIndexPath: indexPath)

    // Reference the video and video title imageview via its tags
    let videoThumbnail = cell.viewWithTag(1) as! UIImageView
    let playlistTitle = cell.viewWithTag(2) as! UILabel
    let playlistVideoCount = cell.viewWithTag(4) as! UILabel

    // User scrolled to last element (i.e. 5th video), so load more results
    if (indexPath.row == playlistItems.count - 1)
    {
        print("indexPath.row = \(indexPath.row)")                  

       getChannelDetails("https://www.googleapis.com/youtube/v3/playlists?pageToken=CAUQAA&part=contentDetails,snippet&channelId=UCJKOvdk-nVzDAFR_9MF64sw&key=\(apiKey)")
    }

    playlistTitle.text = ( (playlistItems[indexPath.row] as! Dictionary<NSObject, AnyObject>)["snippet"] as! Dictionary<NSObject, AnyObject>)["title"] as? String

    playlistVideoCount.text = String ( ( ( ( playlistItems[indexPath.row] as! Dictionary<NSObject, AnyObject>)["contentDetails"] as! Dictionary<NSObject, AnyObject>)["itemCount"]!.integerValue ) ) + " Videos"

    videoThumbnail.image = UIImage(data: NSData(contentsOfURL: NSURL(string: ( ( ( (playlistItems[indexPath.row] as! Dictionary<NSObject, AnyObject> )["snippet"] as! Dictionary<NSObject, AnyObject> )["thumbnails"] as! Dictionary<NSObject, AnyObject> )["high"] as! Dictionary<NSObject, AnyObject> )["url"] as! String )! )! )


    return cell
}

func getChannelDetails(urlString: String)
{   
    let targetURL = NSURL(string: urlString)

    performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in

        if HTTPStatusCode == 200 && error == nil
        {
            // Check for valid JSON data by checking for HTTP status code and the error object
            do
            {
                // Convert the JSON data to a dictionary.
                let resultsDict = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! Dictionary<NSObject, AnyObject>

                // Get the first dictionary item from the returned items (usually there's just one item).
                let items = resultsDict["items"] as AnyObject!

                // Loop through all items and add it to another dictionary
                for (var i = 0; i < self.items!.count; i++)
                {
                    self.playlistItems.append(items[i])
                }

                // Reload the tableview.
                self.videosTableView.reloadData()

                // Hide the progress indicator
                self.progressView.hidden = true
            }
            catch
            {
                print(error)
            }
        }
        else
        {
            print("HTTP Status Code = \(HTTPStatusCode)")
            print("Error while loading channel details: \(error)")
        }
    })
}

// Make GET Request
func performGetRequest(targetURL: NSURL!, completion: (data: NSData?, HTTPStatusCode: Int, error: NSError?) -> Void)
{
    // Create a NSMutableURLRequest object using the parameter URL object
    let request = NSMutableURLRequest(URL: targetURL)

    // Set the GET as the preferred HTTP request method
    request.HTTPMethod = "GET"

    // NSURLSessionConfiguration object
    let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()

    // Pass the object as a parameter to the initialization of the NSURLSession
    let session = NSURLSession(configuration: sessionConfiguration)

    // Instantiate a data task object using the session instance, in which we provide the request as an argument
    let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            completion(data: data, HTTPStatusCode: (response as! NSHTTPURLResponse).statusCode, error: error)
        })
    })

    // Start the fetching process of the data task.
    task.resume()
}

感谢。

1 个答案:

答案 0 :(得分:1)

查看performGetRequest的实施详细信息会很有帮助,但您很可能正在使用NSURLSession iOS API。 Quite a few places in iOS execute off the main thread,最终,您的performGetRequest正在执行主线程。如果performGetRequest没有执行主线程,那么你必须改变它。因此,您正在处理多线程,作为解决方案的一部分,用于一个活泼的U.I。

<强>更新

@Dave Batton是正确的,您需要在初始调用getChannelDetails时加载50-100条记录,并确保显示Progress Spinner并且不会随时阻止主线程,以便U.I.没有冻结。您的代码没有阻止主线程,请恢复我建议的更改:

现在我已经看过你的performGetRequest,将你的代码更改回你的方式,我留下了几条评论:

func getChannelDetails(urlString: String)
{   
    let targetURL = NSURL(string: urlString)

    //you are leaving the main thread somewhere in performGetRequest
    performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in

         //this closure is called on the main thread sometime later
         //this is the main thread again, because performGetRequest puts your call back function back on the main thread, all this code is fine.
        if HTTPStatusCode == 200 && error == nil
        {
            // Check for valid JSON data by checking for HTTP status code and the error object
            do
            {
                // Convert the JSON data to a dictionary.
                let resultsDict = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! Dictionary<NSObject, AnyObject>

                // Get the first dictionary item from the returned items (usually there's just one item).
                let items = resultsDict["items"] as AnyObject!

                // Loop through all items and add it to another dictionary
                for (var i = 0; i < self.items!.count; i++)
                {
                    self.playlistItems.append(items[i])
                }

                // Reload the tableview.
                self.videosTableView.reloadData()

                // Hide the progress indicator
                self.progressView.hidden = true

            }
            catch
            {
                print(error)
            }
        }
        else
        {
            print("HTTP Status Code = \(HTTPStatusCode)")
            print("Error while loading channel details: \(error)")
        }
    })

    //so there is actually a return here back to the line you called      getChannelDetails this happens before the code above in the closure is called.
}