简体   繁体   English

Objective-C可可如何在GCD中正确使用运行循环

[英]Objective-C Cocoa how to correctly use run loop in GCD

I'm not sure how to correctly use GCD in a run loop situation where the thread might need to be stopped. 我不确定在可能需要停止线程的运行循环情况下如何正确使用GCD。 The problem starts from the outset, and how or where to use CGEventCallback (which is absent from my code). 问题从一开始就开始了,以及如何或在哪里使用CGEventCallback(我的代码中没有)。 The stop button won't stop the loop, and I don't think my dispatch queue is setup properly -- along with the while loop creating a huge lag. 停止按钮不会停止循环,而且我认为我的调度队列设置不正确-加上while循环会造成巨大的滞后。

I've read top question-answers from the search, like this and this , but one is for iOS and the other isn't relevant. 我已经阅读了搜索中的热门问答,例如thisthis ,但是其中一个是针对iOS的,另一个则无关。 Could someone show me how to properly do this? 有人可以告诉我如何正确执行此操作吗?

my code: 我的代码:

// .h // 。H

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate> {

    IBOutlet NSTextField *textFieldBox;
    IBOutlet NSButton *stop;
}

@property (assign) IBOutlet NSWindow *window;

- (void)stop;

@end

// .m // .m

#import "AppDelegate.h"

@implementation AppDelegate

BOOL isActive = FALSE;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [self mainMethod];
}

- (void)mainMethod {

    NSLog(@"loop started");
    isActive = TRUE;
    [self theArbitraryNonCompliantLoop];
    NSLog(@"doing other stuff");
}

- (void)stop {

    isActive = FALSE;
    return;
}

- (void)theArbitraryNonCompliantLoop {

    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(backgroundQueue, ^{

        while (isActive) {
        for (NSUInteger i = 0; i < 1000000; i++) {
            [textFieldBox setStringValue:[NSString stringWithFormat:@"%lu",(unsigned long)i]];
            }
        }
    });
}

@end

Big mistake: You are changing a UI element on a background thread. 大错误:您正在更改后台线程上的UI元素。 That will cause all kinds of problems. 那会引起各种各样的问题。 Don't do that. 不要那样做

You seem to be quite confused what a runloop is. 您似乎很困惑什么是运行循环。 You are also trying to confuse people by calling something "theRunLoop" that just does stuff on a background thread. 您还试图通过调用仅在后台线程中执行操作的“ theRunLoop”来使人们感到困惑。 Your code has nothing to do with the runloop, and until you understand what a runloop is, better keep away from it. 您的代码与Runloop无关,在您了解Runloop是什么之前,最好远离它。

Ignoring the name, the for loop needs to test isActive as well. 忽略名称,for循环也需要测试isActive That will solve the latency issue. 这样可以解决延迟问题。

The UI update needs to be done on the main thread which is easy because you can just schedule a block on the main queue to do it. UI更新需要在主线程上完成,这很容易,因为您只需在主队列上安排一个块即可。

- (void)theArbitraryNonCompliantLoop {

    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(backgroundQueue, ^{

        while (isActive) 
        {
            for (NSUInteger i = 0; isActive && i < 1000000; i++) 
            {
                dispatch_async(dispatch_get_main_queue(),
                               ^{ [textFieldBox setStringValue:[NSString stringWithFormat:@"%lu",(unsigned long)i]] };
            }
        }
    });
}

There are still some issues here. 这里仍然有一些问题。 I think, as it stands it will flood the main thread's run loop with events, so some throttling will be required. 我认为,就目前情况而言,它将使事件充满主线程的运行循环,因此将需要进行一些限制。 You might also consider some synchronisation for the inActive instance variable in case the compiler optimises it by pulling it into a register at the beginning of the method. 您还可以考虑对inActive实例变量进行一些同步,以防编译器在方法开始时通过将其拉入寄存器来对其进行优化。 Also, it will be subject to race conditions thanks to caching etc. 此外,由于缓存等原因,它也会受到竞争条件的影响。

Why would you call an arbitrary method theRunLoop ? 为什么要调用theRunLoop的任意方法?

Either way, quoting Run Loops ( Threading Programming Guide ): 无论哪种方式,都引用运行循环 (《 线程编程指南》 ):

Both Cocoa and Core Foundation provide run loop objects to help you configure and manage your thread's run loop. Cocoa和Core Foundation都提供了运行循环对象,以帮助您配置和管理线程的运行循环。 Your application does not need to create these objects explicitly; 您的应用程序不需要显式创建这些对象。 each thread, including the application's main thread, has an associated run loop object. 每个线程(包括应用程序的主线程)都有一个关联的运行循环对象。 Only secondary threads need to run their run loop explicitly, however. 但是,只有辅助线程需要显式地运行其运行循环。 The app frameworks automatically set up and run the run loop on the main thread as part of the application startup process. 在应用程序启动过程中,应用程序框架会自动在主线程上设置并运行运行循环。

My guess would be that your while loop is still on its first run. 我的猜测是您的while循环仍处于首次运行状态。 The 1000000 for loop is probably taking too long which is why it still seems like the loop is still running. 1000000 for循环可能花费的时间太长,这就是为什么看起来循环仍在运行的原因。 To test it out put an NSLog after your for loop to see if it has exited it after you changed isActive to false. 要测试它,请将NSLog放在for循环之后,查看将isActive更改为false后是否退出了它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM