Objective-C,使用 UI 事件取消调度队列 [英] Objective-C, cancel a dispatch queue using UI event

查看:36
本文介绍了Objective-C,使用 UI 事件取消调度队列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景:

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

  • User taps a button asking for some kind of modification on address book.
  • A method is called to start this modification and an alert view is shown.
  • In order to show the alert view and keep the UI responsive, I used dispatch_queue:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                 dispatch_sync(dispatch_get_main_queue(), ^{
                   // Show the alert view
                 });
               });

  • 开始修改地址簿的过程:

  • Start the process of address book modification using:

    dispatch_async(modifyingAddressBookQueue, ^{});
    

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

    Now, I want to provide the user with the ability to cancel the process anytime (of course before saving the address book). So when he taps the cancel button in the alert sheet, I want to access the dispatch block, set some certain BOOL to stop the process and revert the address book.

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

    The problem is, you can't do that! you can't access the block and change any variable inside it since all variables are copied only once. Any change of variables inside the block while being executed won't be seen by the block.

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

    To sum up: How to stop a going operation using a UI event?

    更新:

    流程代码:

    - (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(我自己的库)委托的代码

    Code for alertview (my own lib) delegate

    - (void) alertViewProgressCancel:(ASAlertViewProgress *)alertView { // This is a private lib.
    
    
        if (cancelledPtr)
        {
            NSLog(@"stopping");
    
            *cancelledPtr = YES;
        }
    
    }
    

    在接口中,我声明

    BOOL*   cancelledPtr;
    

    更新 2:

    这真的很令人沮丧!对于以下代码

    It's getting really frustrating! for the following code

    for (NSMutableDictionary *contactDictionary in _contactArray) {
    
                NSLog(@"%d", _cancelModification);
                if (_cancelModification) {
                    break;
                }
    }
    

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

    if _cancelModification is set to YES, the for loop is broken and that's OK. Once I comment out the NSLog line, the _cancelModification is neglected when it changes to YES!

    推荐答案

    如果你使用 __block 声明你的 BOOL,那么它可以在块执行之外改变,并且块将看到新值.请参阅 文档了解更多详情.

    If you declare your BOOL using __block, then it can be changed outside of the block execution, and the block will see the new value. See the documentation for more details.

    示例:

    @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.该块将隐式复制 self 并通过它访问 ivar.不需要 __block.

    Alternatively, use an ivar in your class to store the BOOL. The block will implicitly make a copy of self and will access the ivar via that. No need for __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
    

    这篇关于Objective-C,使用 UI 事件取消调度队列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆