Objective c 不使用块的异步调度

Objective c 不使用块的异步调度,objective-c,grand-central-dispatch,dispatch-async,Objective C,Grand Central Dispatch,Dispatch Async,我想使用dispatch_async偶尔每隔60秒从我的web服务器中提取一个不断变化的资源 我想使用dispatch_async,但我想给它一个函数名。因为我想让这个函数休眠并再次重做同样的事情 这就是我试图执行的任务:分派asyncself.downloadQueue,@selectorgetDataThread:;这是不可编译的 我认为while循环不是一个好主意,所以我想知道什么是最好的方法,比如 NSTimer *timer = [NSTimer timerWithTimeInterv

我想使用dispatch_async偶尔每隔60秒从我的web服务器中提取一个不断变化的资源

我想使用dispatch_async,但我想给它一个函数名。因为我想让这个函数休眠并再次重做同样的事情

这就是我试图执行的任务:分派asyncself.downloadQueue,@selectorgetDataThread:;这是不可编译的


我认为while循环不是一个好主意,所以我想知道什么是最好的方法,比如

NSTimer *timer = [NSTimer timerWithTimeInterval:60 target:self selector:@selector(getDataThread:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

- (void)getDataThread:(id)foo {
    dispatch_async(self.downloadQueue, ^{
       // code you want to run asynchronously
    });
}
似乎您想要一些代码块异步运行。。。但是你想让它也以一个定时的间隔运行,所以我认为这应该足够了


如果您想完全放弃块并分派异步,您可以查看NSOperationQueue,请记住NSOperationQueue是基于GCD构建的,但您不必担心直接与它接口。

类似于

NSTimer *timer = [NSTimer timerWithTimeInterval:60 target:self selector:@selector(getDataThread:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

- (void)getDataThread:(id)foo {
    dispatch_async(self.downloadQueue, ^{
       // code you want to run asynchronously
    });
}
似乎您想要一些代码块异步运行。。。但是你想让它也以一个定时的间隔运行,所以我认为这应该足够了


如果您想完全放弃块并分派异步,您可以查看NSOperationQueue,请记住NSOperationQueue是建立在GCD上的,但您不必担心直接与它接口。

有几个观察结果:

如果要为分派的操作创建计时器,请创建类型为dispatch\u source\u type\u timer的分派\u source\t,例如,定义两个类属性:

@property (nonatomic, strong) dispatch_queue_t  queue;
@property (nonatomic, strong) dispatch_source_t timer;
然后创建计时器:

- (void)createTimer
{
    self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    if (self.timer)
    {
        dispatch_source_set_timer(self.timer,
                                  dispatch_walltime(NULL, 0),
                                  60ull * NSEC_PER_SEC,
                                  1ull * NSEC_PER_SEC);

        dispatch_source_set_event_handler(self.timer, ^{
            NSLog(@"doing something");
        });

        dispatch_resume(self.timer);
    }
}
顺便说一句,与所有重复计时器一样,最好在ViewDidDisplay中创建,并在ViewDidEnglishe中删除:

如果不想使用块,请使用任何GCD函数的_f等效函数。所有采用块的GCD函数都有一个格式副本,后缀为_f,该格式副本采用C函数。例如,使用上述示例,非块格式副本如下所示:

- (void)createTimer
{
    self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    if (self.timer)
    {
        dispatch_source_set_timer(self.timer,
                                  dispatch_walltime(NULL, 0),
                                  60ull * NSEC_PER_SEC,
                                  1ull * NSEC_PER_SEC);

        dispatch_source_set_event_handler_f(self.timer, &myTimerHandler);

        dispatch_resume(self.timer);
    }
}

void myTimerHandler(void *context)
{
     NSLog(@"doing something");
}
如果您希望使用使用Objective-C方法而不是C函数的NSTimer,则可能具有以下属性:

@property (nonatomic, strong) dispatch_queue_t  queue;
@property (nonatomic, strong) NSTimer *timer;
然后在视图出现时创建计时器,并在视图消失时将其删除:

- (void)viewDidAppear:(BOOL)animated
{
    self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
    self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [self.timer invalidate];
}

- (void)handleTimer:(NSTimer *)timer
{
    dispatch_async(self.queue, ^{
        NSLog(@"doing something");
    });
}
就个人而言,如果您经常检查这一点,那么您每60秒不断向下拉数据的拉式体系结构可能就没有意义了。您可以考虑向服务器打开一个套接字,并在数据更新时通知服务器,或者使用推送通知来讨论本地通知和推送通知,但是对于这个应用程序,您将查看推送通知。显然,这两者都需要更多的服务器开发,但在架构上更加优雅/高效

顺便说一下,如果您打算每60秒触发一次网络事件,如果您正在通过NSTimer方法3异步启动网络活动,或者如果您的网络请求本身,异步运行您可能还希望引入一些检查,以确保在启动另一个请求之前已完成上一个请求。这是极不可能的,它不会,但你应该检查这一点,尽管如此。如果使用dispatch\u source\u create方法并使用同步网络请求,这不是问题,因为在前一个计时器完成之前,不会重新触发计时器,但在其他情况下,您可能需要小心不要用网络请求备份队列


以下是几点观察:

如果要为分派的操作创建计时器,请创建类型为dispatch\u source\u type\u timer的分派\u source\t,例如,定义两个类属性:

@property (nonatomic, strong) dispatch_queue_t  queue;
@property (nonatomic, strong) dispatch_source_t timer;
然后创建计时器:

- (void)createTimer
{
    self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    if (self.timer)
    {
        dispatch_source_set_timer(self.timer,
                                  dispatch_walltime(NULL, 0),
                                  60ull * NSEC_PER_SEC,
                                  1ull * NSEC_PER_SEC);

        dispatch_source_set_event_handler(self.timer, ^{
            NSLog(@"doing something");
        });

        dispatch_resume(self.timer);
    }
}
顺便说一句,与所有重复计时器一样,最好在ViewDidDisplay中创建,并在ViewDidEnglishe中删除:

如果不想使用块,请使用任何GCD函数的_f等效函数。所有采用块的GCD函数都有一个格式副本,后缀为_f,该格式副本采用C函数。例如,使用上述示例,非块格式副本如下所示:

- (void)createTimer
{
    self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    if (self.timer)
    {
        dispatch_source_set_timer(self.timer,
                                  dispatch_walltime(NULL, 0),
                                  60ull * NSEC_PER_SEC,
                                  1ull * NSEC_PER_SEC);

        dispatch_source_set_event_handler_f(self.timer, &myTimerHandler);

        dispatch_resume(self.timer);
    }
}

void myTimerHandler(void *context)
{
     NSLog(@"doing something");
}
如果您希望使用使用Objective-C方法而不是C函数的NSTimer,则可能具有以下属性:

@property (nonatomic, strong) dispatch_queue_t  queue;
@property (nonatomic, strong) NSTimer *timer;
然后在视图出现时创建计时器,并在视图消失时将其删除:

- (void)viewDidAppear:(BOOL)animated
{
    self.queue = dispatch_queue_create("com.stackoverflow.16782529", 0);
    self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [self.timer invalidate];
}

- (void)handleTimer:(NSTimer *)timer
{
    dispatch_async(self.queue, ^{
        NSLog(@"doing something");
    });
}
就个人而言,如果您经常检查这一点,那么您每60秒不断向下拉数据的拉式体系结构可能就没有意义了。您可以考虑向服务器打开一个套接字,并在数据更新时通知服务器,或者使用推送通知来讨论本地通知和推送通知,但是对于这个应用程序,您将查看推送通知。显然,这两者都需要更多的服务器开发,但在架构上更加优雅/高效

顺便说一下,如果您打算每60秒触发一次网络事件,如果 您正在通过3的NSTimer方法异步启动网络活动,或者如果网络请求本身异步运行,您可能还需要引入一些检查,以确保在启动另一个请求之前已完成上一个请求。这是极不可能的,它不会,但你应该检查这一点,尽管如此。如果使用dispatch\u source\u create方法并使用同步网络请求,这不是问题,因为在前一个计时器完成之前,不会重新触发计时器,但在其他情况下,您可能需要小心不要用网络请求备份队列



太棒了,我觉得应该行得通。我希望只要应用程序打开,这种情况就会发生。我可以把它放在didFinishLaunchingWithOptions中吗?当然,我认为应该可以,不过我会将它包装在一个方法中,并将它放在applicationWillEnterForeground:中,然后在ApplicationIdentinterBackground.下停止计时器。如何停止计时器?@Jamesata要取消计时器,请将NSTimer保留在一个类变量中,然后调用[timer invalidate];。这一点非常重要,否则重复计时器可能会导致保留循环。不要尝试在Dealoc中执行此操作,而是使用类似ViewDidDesive的方法来消除对您的业务逻辑有意义的内容。我不确定您为什么要创建计时器并将其添加到运行循环中。为什么不只是计时器=[NSTimer scheduledTimerWithTimeInterval:60.0目标:自选择器:@selectorgetDataMethod用户信息:无重复:是];它创建了计时器并为您安排了时间?太棒了,我认为应该可以。我希望只要应用程序打开,就会发生这种情况。我可以将其放在didFinishLaunchingWithOptions中吗?当然,我认为这应该可以,不过我会将其包装在一个方法中,并将其放在ApplicationWilenterForeground:中,然后在ApplicationIdentinterB下停止计时器背景:。如何停止计时器?@jamesatha要取消计时器,请将NSTimer保留在类变量中,然后调用[timer invalidate]这一点非常重要,否则重复计时器会导致一个保留周期。不要尝试在dealloc中执行此操作,而是执行类似ViewDidDesive的操作,以消除对您的业务逻辑有意义的内容。我不确定您为什么要创建计时器并将其添加到运行循环中。为什么不只是计时器=[NSTimer scheduledTimerWithTimeInterval:60.0目标:自选择器:@selectorgetDataMethod用户信息:无重复:是];它创建计时器并为您安排时间?如果您可以将其重构为C函数,您可以使用dispatch_async_fIf将其重构为C函数,您可以使用dispatch_async_fA dispatch_source_t在Xcode 7.1.1中不能是强的或保留的。您的代码将不会编译。@Cœur-不,这不是真的。如果您看到这个错误,可能是错误因为您设置了编译器标志-DOS_OBJECT_USE_OBJC=0,如中所述,它关闭了GCD类型的对象行为。但我在Xcode 7.1.1和Xcode 7.2 beta 3中重新测试了这一点,strong运行良好,事实上是必需的。我的系统中没有标志OS_OBJECT_USE_OBJCproject@Cœur-如果您以操作系统为目标,也会出现此错误10.8之前的X版本或6之前的iOS版本,因为它们早于GCD类型的对象处理,因此需要手动分派保留和分派发布。确实,我的目标是iOS 5.1.1。有没有关于如何解决编译错误的想法?分派源代码在Xcode 7.1.1中不能是强的或保留的。您的代码将不会编译。@Cœur-没有,that不是真的。如果你看到了这个错误,可能是因为你设置了编译器标志-DOS_OBJECT_USE_OBJC=0,如中所述,它关闭了GCD类型的对象行为。但是我在Xcode 7.1.1和Xcode 7.2 beta 3中重新测试了这一点,strong运行良好,事实上是必需的。我的项目中没有OS_OBJECT_USE_OBJC标志ct@Cœur-如果目标是10.8之前的OS X版本或6之前的iOS版本,也会出现此错误,因为这早于GCD类型的对象处理,因此需要手动分派_retain和分派_release。是的,我的目标是iOS 5.1.1。您知道如何解决编译错误吗?