ios - 延迟 RACSignal 直到 UIScrollView 不拖动、跟踪或减速

标签 ios uiscrollview reactive-cocoa racsignal

这样可以吗?

- (RACSignal *)deferRefreshSignalUntilScrollViewIsNotBusy:(RACSignal *)infiniteSignal
{
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        __block BOOL disposed = NO;
        RACDisposable *disposable = [infiniteSignal subscribeNext:^(id originalValue) {
            dispatch_repeated(0.0, 0.5, dispatch_get_main_queue(), ^(BOOL *stop) {

                BOOL scrollViewIsBusy = self.scrollView.isTracking
                   || self.scrollView.isDecelerating
                   || self.scrollView.isDragging
                   || _flags.animatingArticlePageScroller;

                *stop = disposed;

                if(!scrollViewIsBusy)
                {
                    [subscriber sendNext:originalValue];
                    *stop = YES;
                }
            });
        }];
        return [RACDisposable disposableWithBlock:^{
            [disposable dispose];
            disposed = YES;
        }];
    }];
}

static void dispatch_repeated_internal(dispatch_time_t firstPopTime, double intervalInSeconds, dispatch_queue_t queue, void(^work)(BOOL *stop))
{    
    __block BOOL shouldStop = NO;
    dispatch_time_t nextPopTime = dispatch_time(firstPopTime, (int64_t)intervalInSeconds * NSEC_PER_SEC);
    dispatch_after(nextPopTime, queue, ^{
        work(&shouldStop);
        if(!shouldStop)
        {
            dispatch_repeated_internal(nextPopTime, intervalInSeconds, queue, work);
        }
    });
}

void dispatch_repeated(double delay, double intervalInSeconds, dispatch_queue_t queue, void(^work)(BOOL *stop))
{
    dispatch_time_t firstPopTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)delay * NSEC_PER_SEC);
    dispatch_repeated_internal(firstPopTime, intervalInSeconds, queue, work);
}

重要的是不要一直轮询 ScrollView 值。仅当您现在有新值时才进行轮询。

最佳答案

  1. 将 ScrollView 的委托(delegate)连接到self(假设selfUIViewController的子类)

    <
  2. 将此代码添加到self... 当 ScrollView 正在滚动时,此信号返回@YES。它将在停止时返回 @NO

    - (RACSignal *)makeScrollViewSignal
    {
        RACSignal *didScroll = [self rac_signalForSelector:@selector(scrollViewDidScroll:) fromProtocol:@protocol(UIScrollViewDelegate)];
        RACSignal *willDrag = [self rac_signalForSelector:@selector(scrollViewWillBeginDragging:) fromProtocol:@protocol(UIScrollViewDelegate)];
        RACSignal *didDrag = [[self rac_signalForSelector:@selector(scrollViewDidEndDragging:willDecelerate:) fromProtocol:@protocol(UIScrollViewDelegate)] filter:^BOOL(RACTuple *tuple) {
            return [tuple.second isEqualToNumber:@NO];
        }];
        RACSignal *didDecelerate = [self rac_signalForSelector:@selector(scrollViewDidEndDecelerating:) fromProtocol:@protocol(UIScrollViewDelegate)];
    
        return [RACSignal merge:@[[didScroll mapReplace:@YES],
                                  [willDrag mapReplace:@YES],
                                  [didDrag mapReplace:@NO],
                                  [didDecelerate mapReplace:@NO],
                                  ]];
    }
    

3A。如果你想丢弃所有 next 除了最新的,...

谢谢Justin Spahr-Summers提供解决方案!

__block BOOL isScrolling = NO;

[self.scrollingSignal subscribeNext:^(NSNumber *isScrollingNumber) {
    isScrolling = [isScrollingNumber boolValue];
}];

// your signal here
[[self.timerSignal throttle:INFINITY valuesPassingTest:^BOOL(id next) {
    return isScrolling;
}] subscribeNext:^(NSNumber *timeInterval) {
    // your work here
    [self log:[NSString stringWithFormat:@"Timer: %ld", [timeInterval integerValue]]];
}];

3B。如果你想接收所有next, ...

解决方案 3B-1

子类 RACQueueScheduler

@interface DelayedScheduler : RACQueueScheduler
@property (nonatomic, strong) dispatch_queue_t delayQueue;
@property (nonatomic, strong) RACDisposable *delayDisposable;
@end


@implementation DelayedScheduler

+ (instancetype)delayedSchedulerWithSignal:(RACSignal *)signal
{
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    DelayedScheduler *obj = [[self alloc] initWithName:@"com.ReactiveCocoa.RACScheduler.delayedMainThreadScheduler" queue:queue];

    obj.delayQueue = queue;
    obj.delayDisposable = [signal subscribeNext:^(NSNumber *delayEnabled) {
        if ([delayEnabled boolValue]) {
            dispatch_suspend(obj.queue);
        } else {
            dispatch_resume(obj.queue);
        }
    } error:^(NSError *error) {
        dispatch_resume(obj.queue);
        obj.delayDisposable = nil;
    } completed:^{
        dispatch_resume(obj.queue);
        obj.delayDisposable = nil;
    }];

    return obj;
}

- (void)dealloc
{
    [self.delayDisposable dispose];
}

@end

然后更改您的信号以在新的调度程序上交付

DelayedScheduler *delayed = [DelayedScheduler delayedSchedulerWithSignal:self.scrollingSignal];
[[self.timerSignal deliverOn:delayed] subscribeNext:^(NSNumber *timeInterval) {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self log:[NSString stringWithFormat:@"%@", timeInterval]];
    });
}];

解决方案 3B-2

将此添加到 viewDidLoad...

[[self makeScrollViewSignal] subscribeNext:^(NSNumber *isScrolling) {
    if ([isScrolling boolValue]) {
        dispatch_suspend(self.queue);
    } else {
        dispatch_resume(self.queue);
    }
}];

// Your signal here... change the `self.timerSignal` to anything else
[self.timerSignal subscribeNext:^(NSNumber *timeInterval) {
    dispatch_async(self.queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            // TODO: add your code here...
            [self log:[NSString stringWithFormat:@"%@", timeInterval]];
        });
    });
}];

关于ios - 延迟 RACSignal 直到 UIScrollView 不拖动、跟踪或减速,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21982274/

相关文章:

ios - Swift 核心数据到自定义 UITableViewCell UILabel 错误

ios - UIViewController 转换与 UIScrollView 到达顶部以启动转换

ios - uiscrollview 中的 UIViewControllers 调用 viewdidappear

iphone - 如何以编程方式强制停止 UIScrollView 中的滚动?

ios - 如何使用 ReactiveCocoa 来满足这种情况

ios - 如何使用 ReactiveSwift 将有错误的信号转换为 NoError 信号? (并且要优雅)

ios - ReactiveCocoa 4 : Observing an Action's completed event

ios - 确定UNNotificationResponse是来自 watch 扩展还是iOS应用

ios - 查找两个时间戳之间的差异 - iOS

ios - 向我的项目添加新 Storyboard