iphone - Objective-C,使用 UI 事件取消调度队列

标签 iphone objective-c ios concurrency grand-central-dispatch

场景:

  • 用户点击一个按钮,要求对地址簿进行某种修改。
  • 调用一个方法来开始此修改并显示一个警报 View 。
  • 为了显示警报 View 并保持 UI 响应,我使用了 dispatch_queue:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                     dispatch_sync(dispatch_get_main_queue(), ^{
                       // Show the alert view
                     });
                   });
    
  • 使用以下命令启动地址簿修改过程:

    dispatch_async(modifyingAddressBookQueue, ^{});
    

现在,我想为用户提供随时取消该过程的能力(当然是在保存地址簿之前)。所以当他点击警报表中的取消按钮时,我想访问调度 block ,设置一些特定的 BOOL 来停止进程并恢复地址簿。

问题是,你不能那样做!您无法访问该 block 并更改其中的任何变量,因为所有变量只复制一次。执行时 block 内变量的任何更改都不会被 block 看到。

总结:如何使用 UI 事件停止正在进行的操作?

更新:

流程代码:

- (void) startFixingModification {

    _fixContacts = YES;
    __block BOOL cancelled = NO;

    dispatch_queue_t modifyingAddressBookQueue;
    modifyingAddressBookQueue = dispatch_queue_create(sModifyingAddressBookQueueIdentifier,
                                                      NULL);

    dispatch_async(modifyingAddressBookQueue, ^{

        for (NSMutableDictionary *contactDictionary in _contactArray) {

            if (!cancelled) {
                break;
            }

            i = i + 1;

            BOOL didFixContact = [self fixNumberInContactDictionary:contactDictionary];
            if (!didFixContact) {
                _fixedNumbers = _fixedNumbers - 1;
            }

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                dispatch_sync(dispatch_get_main_queue(), ^{
                    [self setAlertViewProgress:i];
                });

            });
        }
    });

    cancelledPtr = &cancelled;

}

alertview(我自己的库)委托(delegate)的代码

- (void) alertViewProgressCancel:(ASAlertViewProgress *)alertView { // This is a private lib.


    if (cancelledPtr)
    {
        NSLog(@"stopping");

        *cancelledPtr = YES;
    }

}

在接口(interface)中,我声明

BOOL*   cancelledPtr;

更新 2:

真的很郁闷!对于以下代码

for (NSMutableDictionary *contactDictionary in _contactArray) {

            NSLog(@"%d", _cancelModification);
            if (_cancelModification) {
                break;
            }
}

如果 _cancelModification 设置为 YES,则 for 循环被破坏,这没关系。一旦我注释掉 NSLog 行,_cancelModification 在更改为 YES 时将被忽略!

最佳答案

如果您使用 __block 声明您的 BOOL,那么它可以在 block 执行之外更改, block 将看到新值。参见 the documentation了解更多详情。

一个例子:

@interface SNViewController ()
{
    BOOL*   cancelledPtr;
}

@end

@implementation SNViewController

- (IBAction)start:(id)sender
{
    __block BOOL cancelled = NO;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (!cancelled) {
            NSLog(@"running");
            sleep(1);
        }        
        NSLog(@"stopped");
    });

    cancelledPtr = &cancelled;
}

- (IBAction)stop:(id)sender
{
    if (cancelledPtr)
    {
        NSLog(@"stopping");

        *cancelledPtr = YES;
    }
}

@end

或者,在您的类中使用一个 ivar 来存储 BOOL。该 block 将隐式复制 self 并通过它访问 ivar。不需要 __block

@interface SNViewController ()
{
    BOOL   cancelled;
}

@end

@implementation SNViewController

- (IBAction)start:(id)sender
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (!cancelled) {
            NSLog(@"running");
            sleep(1);
        }        
        NSLog(@"stopped");
    });
}

- (IBAction)stop:(id)sender
{
    NSLog(@"stopping");
    cancelled = YES;
}

@end

关于iphone - Objective-C,使用 UI 事件取消调度队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10066897/

相关文章:

iphone - 访问关系的计数会引发错误吗?

ios - [__NSCFNumber countByEnumeratingWithState:objects:count:]:无法识别的选择器已发送到实例

iphone - __block 变量未保留

ios - 有没有一种方法可以使用 Delphi XE5/iOS7 在 iOS 键盘上切换 Shift 键

ios - 带有后退按钮的导航栏中的 UISegmentedControl

c# - C# 接口(interface)和 Objective-C 协议(protocol)有什么区别?

objective-c - 高效持续地向核心数据导入海量数据

ios - 解读崩溃报告 - iOS - xCode

ios - Swift 中的prepareForSegue 正在更改passAlongID 和passAlongRow 的值

iphone - 如何删除 UIWindow?