Pertanyaan Lakukan aksi pada jam, setiap jam, dengan ReactiveCocoa


Berusaha mengikuti praktik terbaik dari ReactiveCocoa untuk memperbarui UI saya pada jam, setiap jam. Ini yang saya punya:

NSDateComponents *components = [[[NSCalendar sharedCalendar] calendar] components:NSMinuteCalendarUnit fromDate:[NSDate date]];
// Generalization, I know (not every hour has 60 minutes, but bear with me).
NSInteger minutesToNextHour = 60 - components.minute;

RACSubject *updateEventSignal = [RACSubject subject];
[updateEventSignal subscribeNext:^(NSDate *now) {
    // Update some UI
}];

[[[RACSignal interval:(60 * minutesToNextHour)] take:1] subscribeNext:^(id x) {
    [updateEventSignal sendNext:x];
    [[RACSignal interval:3600] subscribeNext:^(id x) {
        [updateEventSignal sendNext:x];
    }];
}];

Ini memiliki beberapa kekurangan yang jelas: langganan dan pengiriman manual, dan itu hanya "terasa salah." Ada gagasan tentang cara menjadikan ini lebih "reaktif"?


11
2018-05-13 13:40


asal


Jawaban:


Anda dapat melakukan ini menggunakan operator vanila sepenuhnya. Ini hanya masalah perebutan dua interval bersama sementara masih melewati kedua nilai mereka, yang mana persisnya -concat: tidak.

Saya akan menulis ulang subjek sebagai berikut:

RACSignal *updateEventSignal = [[[RACSignal
    interval:(60 * minutesToNextHour)]
    take:1]
    concat:[RACSignal interval:3600]];

Ini mungkin tidak memberikan Anda presisi presisi yang sangat ultra (karena mungkin ada sedikit cegukan di antara dua sinyal), tetapi seharusnya cukup baik untuk setiap pekerjaan UI.


20
2018-05-14 05:37



Kedengarannya seperti Anda membutuhkan sesuatu seperti +interval:startingIn:.

Dengan pemikiran itu, Anda bisa membuat versi Anda sendiri +interval:startingIn: dengan sedikit mengutak-atik implementasi dari +interval:.

+ (RACSignal *)interval:(NSTimeInterval)interval startingIn:(NSTimeInterval)delay {
  return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {

    int64_t intervalInNanoSecs = (int64_t)(interval * NSEC_PER_SEC);
    int64_t delayInNanoSecs = (int64_t)(delay * NSEC_PER_SEC);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, delayInNanoSecs), (uint64_t)intervalInNanoSecs, (uint64_t)0);
    dispatch_source_set_event_handler(timer, ^{
      [subscriber sendNext:[NSDate date]];
    });
    dispatch_resume(timer);

    return [RACDisposable disposableWithBlock:^{
      dispatch_source_cancel(timer);
      dispatch_release(timer);
    }];
  }] setNameWithFormat:@"+interval: %f startingIn: %f", (double)interval, (double)delay];
}

Dengan ini di tempat, kode Anda bisa refactored ke:

NSDateComponents *components = [[[NSCalendar sharedCalendar] calendar] components:NSMinuteCalendarUnit fromDate:[NSDate date]];
// Generalization, I know (not every hour has 60 minutes, but bear with me).
NSInteger minutesToNextHour = 60 - components.minute;

RACSubject *updateEventSignal = [[RACSignal interval:3600 startingIn:(minutesToNextHour * 60)];
[updateEventSignal subscribeNext:^(NSDate *now) {
    // Update some UI
}];

5
2018-05-13 20:54