从 URL 字符串中提取的 UITableViewController 中的图像加载缓慢

Posted

技术标签:

【中文标题】从 URL 字符串中提取的 UITableViewController 中的图像加载缓慢【英文标题】:Slow loading of images in UITableViewController extracted from URL string 【发布时间】:2016-07-03 04:23:38 【问题描述】:

我正在尝试将从 Web URL 提取的图像加载到每个单元格的图像视图中。

但是,当我滚动表格时,屏幕会冻结,因为我相信它正试图逐个抓取每个单元格的图像。

有没有办法让它异步?由于我在 Swift 2 上运行,当前可用的资源已过时或不兼容(运行 obj c)

我在表格视图控制器中使用的相关代码如下:

override func tableView(newsFeedTableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    let blogPost: BlogPost = blogPosts[indexPath.row]
    cell.textLabel?.text = blogPost.postTitle
    let unformattedDate = blogPost.postDate
    //FORMATTING: Splitting of raw data into arrays based on delimiter '+" to print only useful information
    let postDateArr = unformattedDate.characters.split$0 == "+".map(String.init)
    cell.detailTextLabel?.text = postDateArr[0]
    let url = NSURL(string: blogPost.postImageUrl)
    let data = NSData(contentsOfURL: url!)
    cell.imageView!.image  = UIImage(data: data!)//WHY SO SLOW!?

    print(blogPost.postImageUrl)

    return cell

【问题讨论】:

您是否尝试过使用dataTaskWithRequest?这使您的加载完全Asynchronous 并且不会冻结您的用户界面。您还可以使用Alamofire 出色地进行异步调用。看看吧。 【参考方案1】:

试试这个

    var image: UIImage
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), () -> Void in
            // Background thread stuff.
            let url = NSURL(string: blogPost.postImageUrl)
            let data = NSData(contentsOfURL: url!)
            image = UIImage(data:data)

            dispatch_async(dispatch_get_main_queue(), () -> Void in
                // Main thread stuff.
                cell.imageView.image  = image
            )
        )

【讨论】:

你可以试试Alamofire【参考方案2】:

让我们稍微清理一下您的代码。首先,您正在尝试清除 viewController 中的所有单元格。这意味着您的应用不会尝试逐个加载每张图片,而是更喜欢将所有内容放在一起。

您需要创建一个名为 PostCell 的单独文件,这将是一种 UITableViewCell。

然后您需要转到您的原型单元并将这些视图元素连接到该 PostCell,就像您将它们添加到任何其他 ViewController 一样。

现在,这里是你的 cellForRowAtIndexPath 函数的新代码:

override func tableView(newsFeedTableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
  let blogPost = blogPosts[indexPath.row]

  if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? PostCell 
    cell.configureCell(blogPost)

    return cell
  

  return UITableViewCell() // You need to do this because of if let

然后在那个 PostCell 上清除这个:

func configureCell(post: BlogPost) 
  this.textLabel.text = post.postTitle
  let postDateArr = unformattedDate.characters.split$0 == "+".map(String.init)
  this.detailTextLabel.text = postDateArr[0]

  // I would add few if let declarations here too, but if you are sure all these forced ! variables do exciest, then its ok
  let url = NSURL(string: blogPost.postImageUrl)
  let data = NSData(contentsOfURL: url!)
  this.imageView.image  = UIImage(data: data!)

或者类似的东西。当您将这些元素连接到您的单元格时,您将获得这些元素的正确变量名称。

这应该会有所帮助。有很多教程如何制作自定义 tableviewcell。他们中的一些人建议将所有声明放在该 cellForRowAtIndexPath 中,但我发现它很快就会出现问题。

所以...我的建议很简单...创建一个自定义的 tableviewcell。

希望这会有所帮助! :)

【讨论】:

【参考方案3】:

要在每个单元格上加载图像,请使用 SDWebImage 第三方库。您可以使用 pod 将其添加为 put pod 'SDWebImage' 它提供了各种方法来加载图像,有缓存或没有异步缓存。使用缓存,您不必担心每次单元格出现在屏幕上时加载图像数据。试试这个

override func tableView(newsFeedTableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 

    if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? PostCell 
    --reset your cell here--
    // cell.imageView.image = nil
     
    cell.imageView.sd_setImageWithURL(YOUR_URL, placeholderImage: UIImage(named: "")) 
   (UIImage img, NSError err, SDImageCacheType cacheType, NSURL imgUrl) -> Void in
        // Do awesome things
   
-- configure your cell here --

【讨论】:

以上是关于从 URL 字符串中提取的 UITableViewController 中的图像加载缓慢的主要内容,如果未能解决你的问题,请参考以下文章

从 URL 中提取部分字符串 - Java Regex

从 url 'path' 中提取的 input_url 解析字符串 'name'

从给定的字符串中提取 url [重复]

java 从一个URL中提取特定子字符串保存

从 url 查询字符串参数中提取单独的值

从 Bigquery 中的 URL 中提取字符串