草庐IT

swift - UITableView:延迟重新加载,直到所有数据都在后台下载

coder 2023-09-09 原文

我一直在努力让我的 tableview 正确加载 .count。我必须找到一种方法来告诉 tableview 仅在我的图像和帖子数组完全填充后才加载。

否则我会一直得到一个

fatal error: Array index out of range

cell.cellImage?.image = imagesArray[indexPath.row]

内部

cellForRowAtIndexPath

输出:

    NUMBER OF POSTS->0
    NUMBER OF IMAGES->0
    NUMBER OF POSTS->0
    NUMBER OF IMAGES->0
    NUMBER OF POSTS->0
    NUMBER OF IMAGES->0
    POSTSARRAY COUNT->1
    POSTSARRAY COUNT->2
    POSTSARRAY COUNT->3
    POSTSARRAY COUNT->4

    NUMBER OF POSTS->4
    NUMBER OF IMAGES->0

    IMAGESARRAY COUNT->1
    IMAGESARRAY COUNT->2
    IMAGESARRAY COUNT->3
    IMAGESARRAY COUNT->4

    NUMBER OF POSTS->4
    NUMBER OF IMAGES->4

代码

    override func viewDidLoad() {
        super.viewDidLoad()

//        myTableView.estimatedRowHeight = 312.0
//        myTableView.rowHeight = UITableViewAutomaticDimension

        var query = PFQuery(className: "Post")
        query.whereKey("hobbieTag", equalTo:"\(selectedHobbie)")
        query.orderByAscending("description")
        query.findObjectsInBackgroundWithBlock
            {
                (objects: [AnyObject]?, error: NSError?) -> Void in

                if error == nil
                {
                    //                println("HOBBIES.COUNT->\(hobbies?.count)")
                    for post in objects!
                    {
                        //GET POST TITLE
                        self.posts.append(post["postText"] as! String)
                        println("POSTSARRAY COUNT->\(self.posts.count)")

                        //TEST IMAGE
                        //var appendImage = UIImage(named: "logoPDF")
                        //self.imagesArray.append(appendImage!)

                        //GET IMAGE FILE
                        let postImageFile = post["postImage"] as? PFFile
                        postImageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in

                            var image = UIImage(data: imageData!)
                            self.imagesArray.append(image!)
                            println("IMAGESARRAY COUNT->\(self.imagesArray.count)")

                            }, progressBlock: { (progress: Int32) -> Void in
//                                println("PROGRESS->\(progress)")
                        })
                    }
                    self.myTableView.reloadData()
                }
                else
                {
                    println(error?.localizedDescription)
                    println(error?.code)
                }
//                self.myTableView.reloadData()
        }//END query
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    override func viewDidAppear(animated: Bool) {
        myTableView.reloadData()
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        println("NUMBER OF POSTS->\(posts.count)")
        println("NUMBER OF IMAGES->\(imagesArray.count)")
        return posts.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cellIdentifier = "Cell"
        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! HobbieFeedTableViewCell

        cell.cellTitle.text = posts[indexPath.row]
        cell.cellSubtitle.text = posts[indexPath.row]


        //        cell.cellImage.image = UIImage(named: "logoPDF")
        //cell.cellImage?.image = imagesArray[indexPath.row]

        return cell
    }

更新代码

        var query = PFQuery(className: "HobbieFeed")
        query.whereKey("hobbieTag", equalTo:"\(selectedHobbie)")
        query.orderByAscending("description")
        query.findObjectsInBackgroundWithBlock
            {
                (objects: [AnyObject]?, error: NSError?) -> Void in

                if error == nil
                {
                    let semaphore = dispatch_semaphore_create(0)

                    //                println("HOBBIES.COUNT->\(hobbies?.count)")
                    for post in objects!
                    {
                        //GET POST TITLE
                        self.posts.append(post["postText"] as! String)
                        println("POSTSARRAY COUNT->\(self.posts.count)")

                        //TEST IMAGE
                        //var appendImage = UIImage(named: "logoPDF")
                        //self.imagesArray.append(appendImage!)

                        //GET IMAGE FILE
                        let postImageFile = post["postImage"] as? PFFile
                        postImageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in

                            var image = UIImage(data: imageData!)
                            self.imagesArray.append(image!)
                            println("IMAGESARRAY COUNT->\(self.imagesArray.count)")

                            dispatch_semaphore_signal(semaphore)

                            }, progressBlock: { (progress: Int32) -> Void in
                                println("PROGRESS->\(progress)")
                        })


                    }

                    // Wait for all image loading tasks to complete
                    for post in objects! {
                        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
                        println("SHAPHORE POSTS COUNT->\(self.posts.count)")
                        println("SEMAPHORE IMAGES COUNT->\(self.imagesArray.count)")
                    }

                    self.myTableView.reloadData()
                }

        }//END query

最佳答案

您正在循环中在后台加载图像,并在循环后立即调用 reloadData。然而,此时后台任务尚未完成。

for post in objects! {
    ...
    // This starts a background operation
    postImageFile?.getDataInBackgroundWithBlock(...)
    ...
}
// The background tasks are not necessarily completed at this point
self.myTableView.reloadData()

要等待所有后台任务完成,您可以使用信号量。这是一个基本示例。

// Create a new semaphore with a value of 0
let semaphore = dispatch_semaphore_create(0)

// Kick off a bunch of background tasks
for i in 0...10 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        sleep(1) // Do some work or sleep

        // Signal the semaphore when the task is done. This increments
        // the semaphore.
        dispatch_semaphore_signal(semaphore)
    }
}

// Wait until all background tasks are done
for i in 0...10 {
    // This waits until the semaphore has a positive value
    // and then decrements it
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}

// This is only executed after all background tasks are done
println("all tasks are done")

注意这个例子可以通过使用调度组来简化。但是,这在您的情况下不是一个选项,因为您使用完成处理程序调用函数而不是直接在队列上执行 block 。

将上述方法应用于您的代码将如下所示。

let semaphore = dispatch_semaphore_create(0) // Create a semaphore (value: 0)

for post in objects! {
    ...
    postImageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
        ... // Do your work

        // Increment the semaphore when the image loading is completed
        dispatch_semaphore_signal(semaphore)
    }, progressBlock: {
        ...
    })
    ...
}

// Wait for all image loading tasks to complete
for post in objects! {
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}

// This is only called after all images have loaded
self.myTableView.reloadData()

关于swift - UITableView:延迟重新加载,直到所有数据都在后台下载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32031190/

有关swift - UITableView:延迟重新加载,直到所有数据都在后台下载的更多相关文章

  1. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  2. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  3. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

  4. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  5. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  6. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  7. ruby - 匹配大写字母并用后续字母填充,直到一定的字符串长度 - 2

    我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种

  8. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  9. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  10. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

随机推荐