在使用youtube api加载我的UITableViewCell中的nextPageToken时,我遇到了一些问题。
加载视图时,单元格会加载默认的5个播放列表,缩略图和播放列表的标题,如下所示:
当用户向下滚动,并且通过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()
}
感谢。
答案 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.
}