在应用程序未处于活动状态时调整信号

时间:2015-07-07 18:33:38

标签: ios objective-c reactive-cocoa

我希望确保RACSignal仅在应用程序处于活动状态时发送事件。应删除后台发送的其他next事件,但是,如果至少发生一个,则应在应用程序进入前台时发送最新事件。

我知道我可以使用UIApplicationState来确定当前状态,并使用UIApplicationDidBecomeActiveNotification来确定应用程序何时进入前台。我无法使用-sample:,因为前景中发生的所有事件都应立即发送。

用例是:外部设备连接到应用程序并与之通信。根据此设备提供的信息,将进行网络请求 - 但不应在后台进行,只有最新数据才有效。

2 个答案:

答案 0 :(得分:0)

这真的很有趣,因此我只是直接跳到代码然后解释它为什么会这样做。

RACSignal * backgroundSignal = [NSNotificationCenter.defaultCenter rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil];
RACSignal * foregroundSignal = [NSNotificationCenter.defaultCenter rac_addObserverForName:UIApplicationWillEnterForegroundNotification object:nil];
[[[[[backgroundSignal mapReplace:@NO] merge:
 [[foregroundSignal mapReplace:@YES] delay:0.1]] startWith:@YES] 
 map:^RACStream *(NSNumber * value) {
    if (value.boolValue)
    {
        return [[RACSignal interval:1 onScheduler:[RACScheduler scheduler]] mapReplace:@"Foreground"];
    }
    return [[[RACSignal interval:10 onScheduler:[RACScheduler scheduler]] mapReplace:@"Background"] sample:foregroundSignal];
 }].switchToLatest subscribeNext:^(id x) {
    NSLog(@"%@", x);
}];

因此,我们将前景和背景信号都用作布尔标志,以确定我们是否在前台,这里是非常香草的东西。

为了避免信号立即切换(以及我们最新的背景信号丢失),我们将前景信号延迟0.1秒。你可以调整这个值来品尝,但这是一个必要的邪恶。

答案 1 :(得分:0)

我认为这是最干净的方法:

RACSignal * backgroundSignal = [NSNotificationCenter.defaultCenter rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil];
RACSignal * foregroundSignal = [NSNotificationCenter.defaultCenter rac_addObserverForName:UIApplicationWillEnterForegroundNotification object:nil];

// This is the signal you are expecting events from. Note the replayLast operator will always remember the last value
RACSignal * eventSignal = [[RACSignal never] replayLast];

// These signals map the background and foreground signals so on the event of going into the foreground the eventsSignal will be sent and nothing if in the background

RACSignal * backgroundReplaceSignal = [backgroundSignal flattenMap:^RACStream* (id: NSObject){ return [RACSignal never]}];
RACSignal * foregroundReplaceSignal = [foregroundSignal flattenMap:^RACStream* (id: NSObject){ return eventSignal}];


// We then simply have to merge and swithchToLatest which will result in us being subscribed to our events signal when in the foreground and an empty signal in the background
[[[RACSignal merge: @[backgroundReplaceSignal,foregroundReplaceSignal]] switchToLatest] subscribeNext:^(id: NSObject) {
    /*You will only get results from the events signal if your app is in the foreground and when it comes into the foreground you will
    get the last evvents signal send because for the replayLast
    */
}];