Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果线程不是主线程,则不会调用Objective-C:[NSObject performSelector:onThread…]_Objective C_Multithreading_Nsthread_Performselector - Fatal编程技术网

如果线程不是主线程,则不会调用Objective-C:[NSObject performSelector:onThread…]

如果线程不是主线程,则不会调用Objective-C:[NSObject performSelector:onThread…],objective-c,multithreading,nsthread,performselector,Objective C,Multithreading,Nsthread,Performselector,类似的问题已经讨论过了。目前的问题和我试图实现的是,在创建函数的线程中对给定对象调用函数。以下是完整的案例: 类A的实例是在给定的NSThread(线程A)(不是主线程)中创建的。实例将其creatingNSThread作为成员变量 类B的实例的一个成员函数在另一个NSThread-线程B中执行,并希望在a的创建线程中调用a的函数。因此,B当前执行的函数发出以下调用: [_a performSelector: @(fun) onThread: _a.creationThr

类似的问题已经讨论过了。目前的问题和我试图实现的是,在创建函数的线程中对给定对象调用函数。以下是完整的案例:

  • 类A的实例是在给定的
    NSThread
    (线程A)(不是主线程)中创建的。实例将其creating
    NSThread
    作为成员变量
  • 类B的实例的一个成员函数在另一个
    NSThread
    -线程B中执行,并希望在a的创建线程中调用a的函数。因此,B当前执行的函数发出以下调用:

    [_a performSelector: @(fun) 
               onThread: _a.creationThread
             withObject: nil
          waitUntilDone: NO];
    
  • 如果A实例的创建线程不是主线程,
    fun
    永远不会被调用。如果创建线程是主线程,则始终调用它。首先,我想知道创建线程实例的线程是否已被销毁,指针是否指向无效线程,但实际上调用线程对象(线程A)上的任何函数都会产生有效结果,并且不会崩溃。此外,根据检查对象是否有效。有什么建议吗


    更新:

    我正在做的是在后台线程上创建计时器:

    _timer = [NSTimer timerWithTimeInterval:60.0 target:self selector:@selector(fun:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
    

    此代码是启动计时器的代码。计时器不会在任何特定的后台线程中启动。恰好创建计时器的函数可以在任何线程中调用。因此,计时器应该以与NSTimer文档所述完全相同的方式失效:“您应该始终从安装计时器的同一线程调用invalidate方法。”

    要在后台线程上运行计时器,您有两个选项

  • 使用调度计时器源:

    @property (nonatomic, strong) dispatch_source_t timer;
    
    然后,您可以将此计时器配置为每两秒启动一次:

    - (void)startTimer {
        dispatch_queue_t queue = dispatch_queue_create("com.domain.app.timer", 0);
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), 2.0 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(self.timer, ^{
            // call whatever you want here
        });
        dispatch_resume(self.timer);
    }
    
    - (void)stopTimer {
        dispatch_cancel(self.timer);
        self.timer = nil;
    }
    
  • 在后台线程上运行
    NSTimer
    。为此,您可以执行以下操作:

    @property (atomic) BOOL shouldKeepRunning;
    @property (nonatomic, strong) NSThread *timerThread;
    @property (nonatomic, strong) NSTimer *timer;
    

    我并不热衷于
    shouldKeepRunning
    状态变量,但如果你看看苹果,它们不鼓励依赖添加源/计时器来运行循环:

    如果希望运行循环终止,则不应使用此方法。相反,使用其他
    run
    方法之一,并在循环中检查自己的其他任意条件。一个简单的例子是:

    BOOL shouldKeepRunning = YES;        // global
    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    

  • 就我个人而言,我建议使用调度计时器方法。

    我想知道(a)你是否启动了线程;(b) 如果你有一个运行循环;和(c)如果有任何东西阻塞该线程。我建议您编辑您的问题,并包含一个问题列表,其中显示线程的创建和开始以及运行循环的开始。请注意,我们不希望看到所有现有代码,而是将其提取到最低限度以重现您的行为。(顺便说一句,GCD使这件事变得容易多了,但我认为您有一些令人信服的理由来使用
    NSThread
    )您可以使用GCD调度计时器源。这些可以从任何线程中取消。首先,我听到你说的,但是有很多地方你可能会出错,所以如果没有看到你做了什么,任何人都不可能帮助你。如果有其他的方法,我们不知道你想做什么,所以很难说。但是,例如,您所要做的就是在后台线程上运行一个计时器,然后使用GCD dispatch timer source()。请编辑描述您正在尝试执行的操作的问题。这不仅仅是将计时器添加到运行循环中。您必须保持run循环处于活动状态(有几种方法可以做到这一点)。但是,说真的,分派计时器源代码是在后台线程上运行计时器的一种非常简单的方法。请注意,在现代ObjC代码中,几乎没有任何理由调用
    [performSelector:onThread:…]
    。非常罕见的是,任何形式的
    NSThread
    都适合现代ObjC。在几乎所有情况下(不包括一些与大型现有pthreads代码库绑定的情况),GCD都提供了更好的工具。使用
    NSThread
    很容易为自己制造问题,虽然没有被弃用,但我们强烈建议不要使用它。更多信息,请参阅。
    BOOL shouldKeepRunning = YES;        // global
    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);