草庐IT

ios - Swift 3- 从主线程更新 UI

coder 2023-09-09 原文

我想在后台线程中加载数据并在主线程中更新 tableview/UI。根据指示here关于线程,我想知道下面的代码是否是解决它的方法。我正在尝试在用户滚动到特定索引时加载更多数据,并希望确保 UI 不会因线程而卡住。谢谢!

 func loadMore () {
    guard !self.reachedEndOfItems else {
        return
    }

    self.offset = self.offset! + 10
    print("load more offset: \(self.offset)")

    var start = 0
    var end = 0


    isPullToRefresh = false

    let userCreds = UserDefaults.standard

    var getReqString = ""


    if userCreds.bool(forKey: "client_journal") == true || userCreds.bool(forKey: "user_journal") == true {

        var pageNum = ""
        if let pgNum = currentPgNum {
            print(pgNum)
            pageNum = String(pgNum)
        }
        var filterEntryType = ""
        if let entryTypeStr = filtEntryType {
            filterEntryType = entryTypeStr
        }

        var filterUserId = ""
        if let userId = filtUserId {
            filterUserId = userId

        }

        getReqString = "https://gethealthie.com/selected_entries.json?page=\(pageNum)&user_id=\(filterUserId)&entry_type=\(filterEntryType)&entry_filter="


    } else {

        if let pgNum = currentPgNum {
            print(pgNum)

            getReqString = "https://gethealthie.com/entries.json?page=\(pgNum)"
        }

    }


        BXProgressHUD.showHUDAddedTo(self.view)
        let request = Alamofire.request(getReqString, method: .get, headers: [
            "access-token": userCreds.object(forKey: "access-token")! as! String,
            "client": userCreds.object(forKey: "client")! as! String,
            "token-type": userCreds.object(forKey: "token-type")! as! String,
            "uid": userCreds.object(forKey: "uid")! as! String,
            "expiry": userCreds.object(forKey: "expiry")! as! String
            ]).responseJSON { (response:DataResponse<Any>) in
                print(response.response)

                let json = JSON(data: response.data!)
                print(json)

                print("yes")
                print(json.count)


                if userCreds.bool(forKey: "client_journal") == true || userCreds.bool(forKey: "user_journal") == true {
                    self.totalEntries = json["entries"].count

                    let totalEntryCount = json["entries"].count
                    start = 0
                    end = totalEntryCount
                } else {
                    self.totalEntries = json["entries"].count

                    let totalEntryCount = json["entries"].count
                    start = 0
                    end = totalEntryCount
                }

                if  self.totalEntries == 0 {
                    BXProgressHUD.hideHUDForView(self.view);

                } else if end <= self.totalEntries {
                    var jourIdx = 0

                    let newPatient = Patient()
                    let newDietitian = Dietitian()


                    for i in start ..< end {


                        let allEntries = json["entries"]
                        print(allEntries)
                        print("Entry count in loadMore is \(allEntries.count)")

                        let entry = allEntries[i]
                        print(entry)

                        let category = entry["category"]
                        print(category)


                        let name = entry["entry_comments"]
                        let k = name["id"]


                        var indexStr = String(i)

                        //entry attributes
                        self.jsonIdx.add(indexStr)

                        self.type.add(entry["type"].stringValue)
                        self.desc.add(entry["description"].stringValue)
                        self.category.add(entry["category"].stringValue)
                        //food cell- metric stat == healthy int
                        self.metric_stat.add(entry["metric_stat"].stringValue)
                        self.dateCreate.add(entry["created_at"].stringValue)
                        self.viewed.add(entry["viewed"].stringValue)
                        self.seenStatusArr.add(entry["viewed"].stringValue)
                        self.comments.add(entry["entry_comments"].rawValue)
                        self.entryType.add(entry["category"].stringValue)
                        //   "category" : entryType as AnyObject]

                        let posterInfo = entry["poster"]
                        let first = posterInfo["first_name"].stringValue
                        let last = posterInfo["last_name"].stringValue
                        let full = first + " " + last
                        self.captionName.add(full)


                        //food cell subcat
                        self.hungerInt.add(entry["percieved_hungriness"].stringValue)
                        self.prehunger.add(entry["ed_prehunger_string"].stringValue)
                        self.posthunger.add(entry["ed_posthunger_string"].stringValue)
                        self.emotions.add(entry["emotions_string"].stringValue)
                        self.reflection.add(entry["reflection"].stringValue)


                        print(self.comments)
                        self.id.add(entry["id"].stringValue)
                        self.entryImages.add(entry["image_url"].stringValue)


                        if i == end - 1 {
                            userCreds.set(json.count, forKey: "oldJsonCount")

                               BXProgressHUD.hideHUDForView(self.view)

                            DispatchQueue.main.async {
                                self.tableView.reloadData()

                            }
                    }


                } else {
                    var reachedEndOfItems = true
                    BXProgressHUD.hideHUDForView(self.view);
                    print("reached the end")
                }

    }

最佳答案

在此处的代码示例中,您将 reloadData 分派(dispatch)到主队列。但这是不必要的,因为 responseJSON 的闭包已经在主队列上运行,所以不需要调度任何东西。因此,您应该删除 reloadData 到主队列的分派(dispatch)。

现在,如果您使用 URLSession,它默认在后台队列上运行闭包,或者如果您明确提供后台队列作为 queue 参数responseJSON,然后,是的,您将分派(dispatch) reloadData 到主队列。但这并不是您需要确保分派(dispatch)到主队列的唯一事情,因为您的模型更新和 HUD 更新也应该在主队列上运行。但这没有实际意义,因为这个 responseJSON 已经在主队列上运行它的完成处理程序。

然后,在评论中,您稍后会询问是否所有这些都在主队列上运行,是否应该像在 a previous question 中那样将它们全部分派(dispatch)到后台队列? (大概是为了避免阻塞主队列)。

事实证明,这不是必需的(也不可取),因为当 responseJSON 完成处理程序中的响应处理在主队列上运行时,网络请求本身是异步执行的。如果您在闭包中执行计算密集型操作,您只会将完成处理程序代码分派(dispatch)到后台队列(或将后台队列指定为 responseJSON 的参数)。但是你不用担心网络请求阻塞主队列。

最重要的是,Alamofire 让这一切变得简单,它异步运行请求,但在主队列上运行其完成处理程序。它消除了您在使用 URLSession 时遇到的许多手动 GCD 代码。

关于ios - Swift 3- 从主线程更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41538232/

有关ios - Swift 3- 从主线程更新 UI的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  7. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  8. objective-c - 在设置 Cocoa Pods 和安装 Ruby 更新时出错 - 2

    我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U

  9. ruby-on-rails - Rails Associations 的更新方法是什么? - 2

    这太简单了,太荒谬了,我在任何地方都找不到关于它的任何信息,包括API文档和Rails源代码:我有一个:belongs_to关联,我开始理解当您没有关联时您在Controller中调用的正常模型方法与您有关联时调用的方法略有不同。例如,我的关联在创建Controller操作时运行良好:@user=current_user@building=Building.new(params[:building])respond_todo|format|if@user.buildings.create(params[:building])#etcetera但我找不到关于更新如何工作的文档:@user

  10. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

随机推荐