2013-05-13 21 views
11

Cố gắng theo dõi best practices của ReactiveCocoa để cập nhật giao diện người dùng của tôi theo giờ, mỗi giờ. Đây là những gì tôi đã có:Thực hiện hành động theo giờ, mỗi giờ, với ReactiveCocoa

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]; 
    }]; 
}]; 

Điều này có một số sai sót rõ ràng: đăng ký và gửi thủ công và chỉ "cảm thấy sai". Bất kỳ ý tưởng về làm thế nào để làm cho điều này "phản ứng" hơn?

Trả lời

20

Bạn có thể làm điều này bằng khai thác hoàn toàn vani. Nó chỉ là một vấn đề của chuỗi hai khoảng thời gian với nhau trong khi vẫn đi qua cả hai giá trị của họ, đó là chính xác những gì -concat: nào.

tôi sẽ viết lại đề tài này như sau:

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

này có thể không cung cấp cho bạn độ chính xác siêu siêu chính xác (vì có thể có một trục trặc nhỏ xíu giữa hai tín hiệu), nhưng nó phải là Đủ ™ Tốt cho bất kỳ công việc giao diện người dùng nào.

5

Có vẻ như bạn cần một cái gì đó như +interval:startingIn:.

Với suy nghĩ đó, bạn có thể tạo phiên bản +interval:startingIn: của riêng mình bằng cách tinh chỉnh một chút implementation of +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]; 
} 

Với điều này tại chỗ, mã của bạn có thể được refactored để:

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 
}]; 
+0

Điều này là thông minh, nhưng chúng tôi thực sự khuyên bạn nên [soạn thảo các toán tử hiện tại] (https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/DesignGuidelines.md#compose-existing-operators-when-possible) bất cứ khi nào có thể, thay vì viết những cái mới từ đầu. Trong số những thứ khác, điều đó có nghĩa là bạn sẽ nhận được bất kỳ sửa lỗi nào miễn phí. –

+0

Tôi nhận ra rằng tôi đã đi lạc lối các khuyến nghị, nhưng thói quen cũ chết cứng. Cảm ơn lời nhắc nhở nhẹ nhàng. –

+0

Đừng lo! Bạn luôn có thể gửi yêu cầu kéo nếu bạn cho rằng nó cũng là tiêu chuẩn. :) –