ios – NSProgress奇怪的行为

ios – NSProgress奇怪的行为,第1张

概述我有一个由几个子任务组成的大任务.我想为这项重大任务添加进度报告. 为此,我想使用NSProgress,并根据类文档,我可以通过使用其子 – 父机制来做这种子任务进展. 所以为了简化它,让我说我有一个由一个子任务组成的大任务(当然在现实生活中会有更多的子任务).这就是我所做的: #define kFractionCompletedKeyPath @"fractionCompleted" - 我有一个由几个子任务组成的大任务.我想为这项重大任务添加进度报告.
为此,我想使用nsprogress,并根据类文档,我可以通过使用其子 – 父机制来做这种子任务进展.

所以为了简化它,让我说我有一个由一个子任务组成的大任务(当然在现实生活中会有更多的子任务).这就是我所做的:

#define kFractionCompletedKeyPath @"fractionCompleted"  - (voID)runBigTask {    _progress = [nsprogress progressWithTotalUnitCount:100]; // 100 is arbitrary     [_progress addobserver:self                forKeyPath:kFractionCompletedKeyPath                   options:NSkeyvalueObservingOptionNew                   context:NulL];    [_progress becomeCurrentWithPendingUnitCount:100];     [self subTask];    [_progress resignCurrent];} - (voID)subTask {    NSManagedobjectContext *parentContext = self.managedobjectContext; // self is AppDelegate in this example    NSManagedobjectContext *bgContext = [[NSManagedobjectContext alloc]initWithConcurrencyType:nsprivateQueueConcurrencyType];    [bgContext setParentContext:parentContext];    [bgContext performBlockAnDWait:^{        NSInteger totalUnit = 1000;        NSInteger completedUnits = 0;        nsprogress *subProgress = [nsprogress progressWithTotalUnitCount:totalUnit];        for (int i=0; i < totalUnit; i++) {               // run some Core Data related code...              completedUnits++;            subProgress.completedUnitCount = completedUnits;        }    }];}      - (voID)observeValueForKeyPath:(Nsstring *)keyPath ofObject:(ID)object change:(NSDictionary *)change context:(voID *)context {    if ([keyPath isEqualToString:kFractionCompletedKeyPath]) {        if ([object isKindOfClass:[nsprogress class]]) {            nsprogress *progress = (nsprogress *)object;            NSLog(@"progress… %f",progress.fractionCompleted);        }    } else {        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];    }}

如您所见,子任务使用背景上下文来运行一些与Core Data相关的代码,而后台上下文使用主上下文作为其父上下文.
这会导致进度的“fractionCompleted”属性出现一些奇怪的KVO.

这是印刷品:

progress… 1.000000 // why???progress… 0.500000 // why?????progress… 1.000000 // why???????progress… 0.666650 // why???????????progress… 0.666990progress… 0.667320progress… 0.667660progress… 0.667990progress… 0.668320...  progress… 1.000000

如你所见,打印以1.0,0.5和1.0开始,然后是0.66?
从这里它正常,并像我期望的那样进入1.0.

我试图理解为什么会发生这种情况,我注意到如果我从背景上下文中删除父上下文,它工作正常!我从0.0升到1.0.

任何想法为什么会发生这种情况?我该如何解决这个问题?

我添加了一个非常simple project以演示此问题(您可以删除setParentContext:调用以查看它没有它可以正常工作)

解决方法 发生这种情况时的堆栈跟踪如下所示:
(lldb) bt* thread #1: tID = 0x81f2,0x0000000105bffcda Foundation`-[nsprogress setTotalUnitCount:],queue = 'com.apple.main-thread',stop reason = breakpoint 1.1  * frame #0: 0x0000000105bffcda Foundation`-[nsprogress setTotalUnitCount:]    frame #1: 0x0000000105bfeb1b Foundation`+[nsprogress progressWithTotalUnitCount:] + 87    frame #2: 0x0000000105a31213 Foundation`_NSReadBytesFromfileWithExtendedAttributes + 287    frame #3: 0x0000000105a3109d Foundation`-[NSData(NSData) initWithContentsOffile:] + 89    frame #4: 0x0000000105a30b40 Foundation`+[NSDictionary(NSDictionary) newWithContentsOf:immutable:] + 101    frame #5: 0x0000000105a5622a Foundation`+[NSDictionary(NSDictionary) dictionaryWithContentsOffile:] + 45    frame #6: 0x00000001043c4560 CoreData`-[NSManagedobjectModelBundle initWithPath:] + 224    frame #7: 0x00000001043c42ed CoreData`-[NSManagedobjectModel initWithContentsOfURL:] + 205    frame #8: 0x00000001040f723f CDProgress`-[AppDelegate managedobjectModel](self=0x00007fbe48c21f90,_cmd=0x000000010459b37b) + 223 at AppDelegate.m:127    frame #9: 0x00000001040f7384 CDProgress`-[AppDelegate persistentStoreCoordinator](self=0x00007fbe48c21f90,_cmd=0x000000010459c1cb) + 228 at AppDelegate.m:142    frame #10: 0x00000001040f708c CDProgress`-[AppDelegate managedobjectContext](self=0x00007fbe48c21f90,_cmd=0x0000000104598f0d) + 92 at AppDelegate.m:111    frame #11: 0x00000001040f6bdb CDProgress`-[AppDelegate subTask](self=0x00007fbe48c21f90,_cmd=0x00000001040f7997) + 43 at AppDelegate.m:45    frame #12: 0x00000001040f6b89 CDProgress`-[AppDelegate runTask](self=0x00007fbe48c21f90,_cmd=0x00000001040f7928) + 233 at AppDelegate.m:40    frame #13: 0x00000001040f6a4b CDProgress`-[AppDelegate application:dIDFinishLaunchingWithOptions:](self=0x00007fbe48c21f90,_cmd=0x0000000104f5dba9,application=0x00007fbe48f00fb0,launchOptions=0x0000000000000000) + 571 at AppDelegate.m:26    frame #14: 0x000000010477c5a5 UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 234    frame #15: 0x000000010477d0ec UIKit`-[UIApplication _callinitializationDelegatesForMainScene:TransitionContext:] + 2463    frame #16: 0x000000010477fe5c UIKit`-[UIApplication _runWithMainScene:TransitionContext:completion:] + 1350    frame #17: 0x000000010477ed22 UIKit`-[UIApplication workspaceDIDEndTransaction:] + 179    frame #18: 0x00000001088092a3 FrontBoardServices`__31-[FBSSerialQueue performAsync:]_block_invoke + 16    frame #19: 0x000000010615fabc CoreFoundation`__CFRUNLOOP_IS_CALliNG_OUT_TO_A_BLOCK__ + 12    frame #20: 0x0000000106155805 CoreFoundation`__CFRunLoopdoblocks + 341    frame #21: 0x00000001061555c5 CoreFoundation`__CFRunLoopRun + 2389    frame #22: 0x0000000106154a06 CoreFoundation`CFRunLoopRunspecific + 470    frame #23: 0x000000010477e799 UIKit`-[UIApplication _run] + 413    frame #24: 0x0000000104781550 UIKit`UIApplicationMain + 1282    frame #25: 0x00000001040f7793 CDProgress`main(argc=1,argv=0x00007fff5bb09308) + 115 at main.m:16    frame #26: 0x000000010686f145 libdyld.dylib`start + 1(lldb)

这里发生的是当加载模型时,它正在读取一个pList文件.读取pList文件调用 – [NSData initWithContentsOffile:],它在主线程上调用[nsprogress progressWithTotalUnitCount:].作为release notes point out,这将创建一个nsprogress,它是当前进步的孩子. initWithContentsOffile:实际上正在执行此 *** 作,并创建您创建的nsprogress的新子项:

<nsprogress: 0x7f9353596f80> : Parent: 0x0 / Fraction completed: 0.0000 / Completed: 0 of 1     <_nsprogressGroup: 0x7f935601a0d0> : Portion of parent: 100 Children: 1      <nsprogress: 0x7f935600bf50> : Parent: 0x7f9353596f80 / Fraction completed: 0.0000 / Completed: 0 of 0

这里发生的事情是在你面前增加了额外的工作.此时,它对您要添加的其他工作一无所知. initWithContentsOffile添加的子项:完成,从树中删除,然后开始添加您的工作.

当前进度从0开始,并且变为100%.您看到100%是因为您的KVO选项不包含NSkeyvalueObservingOptionInitial.

NSData添加从0开始的子进度,并转到100%.

您的核心数据任务会添加一个从0开始并且(最终)达到100%的子项.

然而,这里的一个关键点是你正在使用performBlockAnDWait:.虽然块本身在专用队列上运行,但此方法将阻止调用线程,这将延迟您的KVO通知. performBlockAnDWait:如果可能的话,还将重用调用线程,这是需要注意的事情.

如果您编辑subTask方法以使用nsprogress包装自身作为整个工作单元的父级,最后重新调整当前状态,您可能会获得更接近您期望的行为:

- (voID)subTask {    nsprogress  *progress   = [nsprogress progressWithTotalUnitCount:1];    NSManagedobjectContext *parentContext = self.managedobjectContext;    NSManagedobjectContext *bgContext = [[NSManagedobjectContext alloc]initWithConcurrencyType:nsprivateQueueConcurrencyType];    [bgContext setParentContext:parentContext];    [progress becomeCurrentWithPendingUnitCount:1];    [bgContext performBlock:^{    ... stuff    [progress resignCurrent];}

nsprogress可能有点困难,但有了一些经验,它会变得更容易.我承诺!

总结

以上是内存溢出为你收集整理的ios – NSProgress奇怪的行为全部内容,希望文章能够帮你解决ios – NSProgress奇怪的行为所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1107767.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-28
下一篇 2022-05-28

发表评论

登录后才能评论

评论列表(0条)

保存