runloop空闲时运行代码

Posted

技术标签:

【中文标题】runloop空闲时运行代码【英文标题】:Running code when the runloop is idle 【发布时间】:2013-02-13 15:40:46 【问题描述】:

我正在寻找类似于

的行为
[[NSNotificationQueue defaultQueue] enqueueNotification:not postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName|NSNotificationCoalescingOnSender forModes:nil];

但不使用通知,以某种方式将选择器或块排入队列而不是通知。

至于我的动机(只是想看看这是否是一种合法的做法)。我在一个视图中添加了多个子视图,显然没有办法知道有多少,所以每次我添加一个子视图时,我都必须通过调用layoutIfNeeded 来执行一些计算,以便以特定的方式布局子视图。现在,我在想,如果我只能在 runloop 空闲时调用该方法(以某种方式推迟调用并合并它),那么在它执行布局计算时所有子视图都已经添加了。希望有道理。

-(void)layoutSubviews

[super layoutSubviews];


UIView* prevView = nil;
for (NSUInteger i=0; i<[self.subviews count]; i++) 
    UIView* view = self.subviews[i];
    CGFloat spacing = prevView!=nil?self.spacing:0;
    view.topLeft = CGPointOffset(prevView.bottomLeft, spacing, 0);
    prevView = view;


[self fitSubviews];

添加了我在 layoutSubview 方法中的代码。

【问题讨论】:

必须有更简单的方法来解决这个问题,比如覆盖layoutSubviews 来测试全局标志(defer_layout)并在第一次调用时启动计时器。然后当计时器触发时,清除defer_layout 标志并实际进行布局。好吧,类似的东西;需要一些技巧,但看起来比你前进的方向更容易实现。 setNeedsLayout 已经推迟和合并——这还不够吗? 有趣的是你指出了@Tommy。因为它确实如此,但是,当我使用它而不是layoutIfNeeded 时,我无法更改layoutSubviews 中的视图大小,我的意思是没有像我最初那样进入无限循环,因为可能setSize: 调用@987654332 @,但它根本不会改变大小(始终为 0) @***foe 这当然不简单 :) 所以你想要做的是sizeThatFits:(因为你不打算直接覆盖sizeToFit)和layoutSubviews的组合,大概是因为它们最终都做得很好几乎相同的计算,所以只做一次工作感觉更整洁? 【参考方案1】:

对于一般问题,最简单的解决方案是:

- (void)setNeedsCustomTask

    // cancel any previously scheduled call to perform the task
    [NSObject
         cancelPreviousPerformRequestsWithTarget:self
         selector:@selector(doCustomTask)
         object:nil];

    // schedule a new call; because you've specified any delay
    // at all this will be scheduled to occur in the future rather than
    // right now and because you've specified a 0.0 delay it'll be
    // as soon as possible in the future
    [self performSelector:@selector(doCustomTask) withObject:nil afterDelay:0.0];


- (void)doCustomTask

    NSLog(@"I am a custom task");

这是因为performSelector:withObject:afterDelay: 将调用安排在未来的runloop 上。您还可以指定inModes:,例如如果您想避免跟踪模式。

在取消和重新安排而不是在手边保留一个标志时,显然存在一些技术上的低效率,但它很整洁,因为您不需要明确地编组状态。所以我认为首先做这件事是一个很好的过早优化论据。

【讨论】:

这是一个巧妙的技巧@Tommy。感谢分享。它解决了我最初的问题,并将记住它以备将来使用。目前,我找到了一种仅使用 setNeedsLayoutlayoutSubviews 对齐子视图的方法,正如您在上面的其中一个 cmets 中提到的那样,它们已经延迟和合并。

以上是关于runloop空闲时运行代码的主要内容,如果未能解决你的问题,请参考以下文章

RunLoop

多线程RunLoop

RunLoop

iOS RunLoop简介

runloop简单介绍

iOS中runloop总结(二)