主视图控制器外的多线程进度条并发问题

     2023-03-05     270

关键词:

【中文标题】主视图控制器外的多线程进度条并发问题【英文标题】:Multi-threaded progress bar concurrency issue outside the main view controller 【发布时间】:2015-10-29 10:02:20 【问题描述】:

我在同一个线程和视图控制器中找到了很多进度条更新解决方案,但它们似乎与我的情况不同。

在我的应用程序中,主视图控制器调用loadIntoCoreData()(在类MyLoadingService 中实现),它通过另一个线程将数据异步加载到核心数据中。这个函数必须不断更新加载百分比(写在NSUserDefaults.standardUserDefaults())到主线程,以便它可以显示在主视图控制器的进度条上。我曾经在MainViewController 中使用过while 循环来不断获取当前百分比值,如下所示:

class MainViewController 

    override func viewDidLoad() 
        MyLoadingService.loadIntoCoreData()  result in 

            NSUserDefaults.standardUserDefaults().setBool(false, forKey: "isLoading")
            // do something to update the view

        
        self.performSelectorInBackground("updateLoadingProgress", withObject: nil)
     

    func updatingLoadingProgress() 
        let prefs = NSUserDefaults.standardUserDefaults()
        prefs.setBool(true, forKey: "isLoading")

        // here I use a while loop to listen to the progress value
        while(prefs.boolForKey("isLoading")) 

            // update progress bar on main thread
            self.performSelectorOnMainThread("showLoadingProcess", withObject: nil, waitUntilDone: true)
        
        prefs.setValue(Float(0), forKey: "loadingProcess")
        

    func showLoadingProcess() 
        let prefs = NSUserDefaults.standardUserDefaults()
        if let percentage = prefs.valueForKey("loadingProcess") 
            self.progressView.setProgress(percentage.floatValue, animated: true)
        
    

并且在函数loadIntoCoreData的类中:

class MyLoadingService 

    let context = (UIApplication.sharedApplication()delegate as! AppDelegate).managedObjectContext!

    func loadIntoCoreData(source: [MyModel]) 
        var counter = 0
        for s in source 
            //load into core data using the class context

            NSOperationQueue.mainQueue.addOperationWithBlock(
                // updating the value of "loadingProcess" in NSUserDefaults.standardUserDefaults() 
                // and synchronize it on main queue
            )
            counter++
        
    

上述代码可以成功运行进度条,但是由于核心数据上下文冲突(认为managedObjectContext没有被主线程触及)。因此,我考虑使用NSOperationQueue.performSelectorOnMainThread 在每次进入后确认主线程,而不是在主线程上使用while 循环。因此我将我的视图控制器作为参数sender 放入loadCoreData 并调用performSelectorOnMainThread("updateProgressBar", withObject: sender, waitUntilDone: true) 但失败并出现错误“无法识别的选择器发送到类'XXXXXXXX'”。所以我想问是否可以在线程之间更新 UI 对象?或者,如何修改我之前的解决方案,以便解决核心数据上下文冲突?任何解决方案都值得赞赏。

class MyLoadingService 
    func loadIntoCoreData(sender: MainViewController, source: [MyModel]) 
        var counter = 0
        for s in source 
            //load into core data using the class context

            NSOperationQueue.mainQueue.addOperationWithBlock(
                // updating the value of "loadingProcess" in NSUserDefaults.standardUserDefaults() 
                // and synchronize it on main queue
            )
            NSOperationQueue.performSelectorOnMainThread("updateProgressBar", withObject: sender, waitUntilDone: true)
            counter++
        
    
    func updateProgressBar(sender: MainViewController) 
        sender.progressView.setProgress(percentage, animated: true)
    


class MainViewController 
    override func viewDidLoad() 
        MyLoadingService.loadIntoCoreData(self)  result in 

            // do something to update the view
        
    
 

【问题讨论】:

【参考方案1】:

首先,您以可怕的方式滥用NSUserDefaults。文档将其描述为...

NSUserDefaults 类为 与默认系统交互。默认系统允许 应用程序自定义其行为以匹配用户的偏好。 例如,您可以允许用户确定哪些单位 测量您的应用程序显示或文档的频率 自动保存。应用程序通过分配记录这些偏好 用户默认数据库中的一组参数的值。这 参数被称为默认值,因为它们通常用于 确定应用程序在启动时的默认状态或其行为方式 默认情况下。

您正在使用它来存储全局变量。

此外,您在循环中完全滥用了用户的 CPU,您不断检查用户默认值中的值,并将选择器剪掉到主线程。 “滥用 CPU”甚至无法描述这段代码在做什么。

您应该使用NSProgress 报告进度。有一个WWDC 2015 presentation 专用于使用NSProgress


关于您的核心数据使用情况。

不幸的是,由于您有意编辑了所有核心数据代码,因此无法说出问题所在。

但是,根据我所看到的,您可能正试图从后台线程使用您的应用程序委托(可能仍使用已弃用的限制策略创建)中的托管对象上下文,这是最高的罪过就核心数据而言的顺序。

如果要将数据导入为长时间运行的操作,请使用私有上下文,并在后台执行操作。使用NSProgress 将进度传达给任何想听的人。


编辑

感谢您对我的核心数据上下文使用的建议。我挖掘了所有 我的代码中的上下文并重新组织了里面的上下文, 冲突问题不再发生。至于 NSProgress ,它是一个 遗憾的是 WWDC 演示文稿侧重于 iOS 9 上的功能(而 我的应用程序必须在 iOS 8 设备上压缩)。但是,即使我使用 NSProgress,我还是应该告诉主线程核心有多少数据 数据(在另一个线程上)已经有了,对吧?线程如何 NSProgress 知道我的核心数据线程的加载进度吗? – 惠特尼13625

您仍然可以在 iOS8 上使用 NSProgress,唯一的区别是您不能显式添加子项,但隐式方式仍然有效,并且该视频也解释了它。

您确实应该观看整个视频而忘记 iOS9 部分,只是要知道您必须隐式添加子代而不是显式添加。

另外,this pre-iOS9 blog 的帖子应该可以解决您对此的任何疑问。

【讨论】:

感谢您对我的核心数据上下文使用的建议。我挖掘了代码中的所有上下文并重新组织了里面的上下文,冲突问题不再发生。至于NSProgress,很遗憾,WWDC 演示集中在 iOS 9 上的功能上(而我的应用程序必须在 iOS 8 设备上压缩)。然而,即使我使用NSProgress,我仍然应该告诉主线程核心数据(在另一个线程上)已经有多少数据,对吧? NSProgress上的线程怎么知道我的核心数据线程的加载进度?

MVC 进度条线程

...worker,但进度条没有更新。我怀疑我的线程有问题。我在控制器中定义的按钮是:classSearchBtnListenerimplementsActionLi 查看详情

需要有关 gtkmm 中的多线程的帮助

】需要有关gtkmm中的多线程的帮助【英文标题】:NeedHelpRegardingmultithreadingingtkmm【发布时间】:2020-09-1006:07:23【问题描述】:我在线程方面不是很差,我需要帮助,我有一个带有进度条的gtkmm窗口,任务是在后台执行多个shell脚本... 查看详情

控制进度条的粗细

】控制进度条的粗细【英文标题】:ControlThicknessofProgressBar【发布时间】:2015-03-1708:37:17【问题描述】:我有一个进度条,如下所示:我的问题很简单,我将如何控制圆形视图的“厚度”,因为在我看来它似乎太厚了。非常感谢... 查看详情

添加视图控制器作为启动屏幕

】添加视图控制器作为启动屏幕【英文标题】:Addingviewcontrolleraslaunchscreen【发布时间】:2015-06-0106:42:24【问题描述】:我正在处理一个启动屏幕,我想在其中添加一个进度条。LaunchScreen.xib不允许我在启动屏幕上添加进度条。那... 查看详情

c#通过线程来控制进度条(转)--讲解多线程对界面的操作

//通过创建委托解决传递参数问题privatevoid_btnRun_Click(objectsender,System.EventArgse){RunTaskDelegaterunTask=newRunTaskDelegate(RunTask);//委托同步调用方式runTask(Convert.ToInt16(_txtSecond.Value));}//通过创建委托解决传递参数问题,通过委托的 查看详情

es内部的多线程异步并发控制

version元数据(1)第一次创建一个document的时候,它的_version版本号是1;以后,每次对这个document执行修改或者删除操作,都会对这个_version版本号自动加1(2)在删除一个document的时候,它不是立即物理删除掉的,它的一些版本号... 查看详情

返回 UIViewController 时不升级进度条

...在正在下载的页面上时一切正常,但是当我转到其他视图控制器并返回我的下载页面时,连接委 查看详情

在循环期间更新进度条

...oop【发布时间】:2017-01-1718:07:30【问题描述】:我有两个控制器。首先,我有一个进度条,并且有一个获取数据和循环的请求。我需要在循环期间更新第一个控制器上的栏。问题是即使它不更新循环,斜杠也只会在方法执行完成... 查看详情

servlet的多线程并发问题

packagegz.itcast.e_thread;importjava.io.IOException;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpS 查看详情

Swift 3:如何为类似于进度条的视图背景颜色设置动画

...2017-06-0221:05:48【问题描述】:当用户进入包含下图的视图控制器时,我希望根据本例中为70的值对蓝色进行动画处理。这意味着,颜色从视图中的0px开始加载,并且停止在任何值的数量上。另外,我希望在加载颜色的同时从0计数... 查看详情

并发请求中的进度条[重复]

】并发请求中的进度条[重复]【英文标题】:Progressbarinconcurrentrequest[duplicate]【发布时间】:2017-11-1405:48:22【问题描述】:我正在我的服务器上发出多个并发请求并且它工作正常。但我想显示所有请求的总进度。我怎样才能做到... 查看详情

动态更新 UIProgressView 的进度

...我的问题是我的最后一个进度条只会更新.....触摸时视图控制器有按钮,开始从ftp服务器下载。立即触摸时导航到另一个视图控制器,其中uitableview显示正在进行的不同下载。我将UIProgres 查看详情

例外:跨线程操作无效:控制'pgImportProcess(进度条)'从一个线程访问,而不是它在[重复]上创建的线程

】例外:跨线程操作无效:控制\\\'pgImportProcess(进度条)\\\'从一个线程访问,而不是它在[重复]上创建的线程【英文标题】:Exception:Cross-threadoperationnotvalid:Control\'pgImportProcess(ProgressBar)\'accessedfromathreadotherthanthethreaditwascreatedon[dup... 查看详情

通过委托函数设置集合视图中进度条的值

】通过委托函数设置集合视图中进度条的值【英文标题】:Setvalueofprogressbarincollectionviewthroughdelegatefunction【发布时间】:2014-06-1403:25:59【问题描述】:我有一个收藏视图。我想更新其单元格中的进度条。我已经对单元格进行了子... 查看详情

如何为 collectionviewcell 内的进度条创建 IBOutlet?

...度条添加一个边框半径,但是每当我将进度条添加到视图控制器时,它都会显示“非法配置”和 查看详情

未来对象的多并发问题

】未来对象的多并发问题【英文标题】:MultipleConcurrencyIssuewithFutureObject【发布时间】:2014-04-3000:24:15【问题描述】:我正在尝试生成一些线程,并在它们执行时将它们放在一个列表中。当他们完成处理时,我想收集他们的结果... 查看详情

c#如何根据文件数量控制进度条

...。如果你使用的StatusBar中的进度条的话,你可以不考虑多线程更新UI的问题,因为它本身已经在内部实现了外部线程更新UI控件的逻辑。但是如果你使用普通的Progressbar控件,那你就得自己处理这部分逻辑,因为控件只能在其所在... 查看详情

用于处理并发用户的多线程 GAE servlet

】用于处理并发用户的多线程GAEservlet【英文标题】:MultithreadGAEservletstohandleconcurrentusers【发布时间】:2013-01-2915:27:15【问题描述】:我想对我的GAEservlet进行多线程处理,以便同一实例上的同一个servlet可以处理多达10个(在前端... 查看详情