Reactivecocoa: ๊ฐ€๋ณ€ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฐ˜๋ณต๋˜๋Š” ์‹ ํ˜ธ

์— ๋งŒ๋“  2015๋…„ 04์›” 01์ผ  ยท  6์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: ReactiveCocoa/ReactiveCocoa

๊ฐ€๋ณ€ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฐ˜๋ณต๋˜๋Š” ์‹ ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์˜ PoC๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

// Repeat.h
#import <Foundation/Foundation.h>

<strong i="6">@interface</strong> Repeat : NSObject

- (instancetype)initWithInterval:(NSInteger)interval;

<strong i="7">@property</strong> (assign, nonatomic) NSInteger interval;
<strong i="8">@property</strong> (readonly, nonatomic) RACSubject *dataSubject;

<strong i="9">@end</strong>
// Repeat.m
#import <ReactiveCocoa/ReactiveCocoa.h>

#import "Repeat.h"

<strong i="12">@interface</strong> Repeat ()

<strong i="13">@property</strong> (readwrite, strong, nonatomic) RACSubject *dataSubject;
<strong i="14">@property</strong> (readwrite, strong, nonatomic) RACSignal *dataSignal;

<strong i="15">@end</strong>

<strong i="16">@implementation</strong> Repeat

- (instancetype)initWithInterval:(NSInteger)interval
{
    self = [super init];
    if (self) {
        self.dataSubject = [RACSubject subject];
        self.dataSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            static int i = 0;
            [subscriber sendNext:@(i++)];
            return nil;
        }];

        self.interval = interval;

        [RACObserve(self, interval) subscribeNext:^(id x) {
            RACSignal *limit = [RACObserve(self, interval) skip:1];
            RACSignal *repeater = [[RACSignal interval:[x integerValue]
                                           onScheduler:[RACScheduler mainThreadScheduler]]
                                   takeUntil:limit];
            RACSignal *tickSignal = [repeater doCompleted:^{
                                         NSLog(@"interval changed to: %lu", self.interval);
                                     }];
            [[tickSignal flattenMap:^RACStream *(id value) { // *
                return self.dataSignal;
            }] subscribeNext:^(id x) {
                [self.dataSubject sendNext:x];
            }];
        }];
    }
    return self;
}

<strong i="17">@end</strong>

์‚ฌ์šฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Repeat *repeater = [[Repeat alloc] initWithInterval:3];
[repeater.dataSubject subscribeNext:^(id x) {
    // do something with x
}];
...
// somehwere else in the code
repeater.interval = 5;

์ด๋ฅผ ํ†ตํ•ด ๊ตฌ๋…์„ ์œ ์ง€ํ•˜๊ณ  ์‹ ํ˜ธ ๊ฐ’ ์ „๋‹ฌ ๊ฐ„๊ฒฉ ๋งŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ๋น„์ž๊ฐ€ ์‹ ํ˜ธ๋ณด๋‹ค๋Š” ์ฃผ์ œ๋ฅผ ์‹ค์ œ๋กœ ๊ตฌ๋…ํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์ด ๊ฑฑ์ •๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๊ณ  ๊ฐ€์ด๋“œ ๋ผ์ธ์€ ์‹ค์ œ๋กœ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์ฃผ์ œ๋ฅผ ํ”ผํ•˜๋„๋ก ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ณต์šฉ ์ธํ„ฐํŽ˜์ด์Šค์— dataSignal ๋ฅผ ๋…ธ์ถœํ•˜๊ณ  // * ๋กœ ํ‘œ์‹œ๋œ ๋ถ€๋ถ„์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ต์ฒดํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

[tickSignal subscribeNext:^(id x) {
    [self.dataSignal replayLast];
}];

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์ „ํ˜€ ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์ดˆ๊ธฐ ๊ฐ’๋งŒ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋‚ด๊ฐ€ ์—ฌ๊ธฐ์„œ ๋‹ฌ์„ฑํ•˜๋ ค๋Š” ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  ์‹œ๋„ ํ–ˆ์Šต๋‹ˆ๊นŒ? RAC๊ฐ€์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•˜๊ณ  ๋‚ด PoC๋Š” ํฌ๊ฒŒ ๊ฐœ์„  ํ•  ์ˆ˜์žˆ๋Š” ์ถ”์•…ํ•œ ์ƒˆ๋ผ ์˜ค๋ฆฌ์ž…๋‹ˆ๋‹ค.

์š”์ ์€ ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค : https://gist.github.com/eimantas/51d9dfc81136f340a829

์—…๋ฐ์ดํŠธ : @jspahrsummers๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ stackoverflow์— ๋Œ€ํ•œ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€ : http://stackoverflow.com/questions/15075075/when-to-use-racreplaysubject-vs-racmulticastconnection

RACMulticastConnection์ด ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. RACSubject ์„ RACSignal ๋กœ ๋…ธ์ถœํ•˜๋ฏ€๋กœ ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

question

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

- (RACSignal *)doStuffRepeatedly {
    return [[[RACSignal
        defer:^{
            // Do some stuff here
            return [RACSignal empty];
        }]
        // Wait 5 seconds
        concat:[RACSignal delay:5]]
        then:^{
            // Do more stuff
            return [self doStuffRepeatedly];
        }];
}

๋ชจ๋“  6 ๋Œ“๊ธ€

ํƒ€์ด๋จธ๊ฐ€ ์‹ค์ œ๋กœ ์ข…๋ฃŒ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ concat:[RACSignal delay:N] ํ•˜๊ณ  ๊ทธ ํ›„์— concat:[RACSignal defer:^{}] ์—์„œ ์ž์ฒด ํ˜ธ์ถœํ•˜๋Š” ์žฌ๊ท€ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋ฌดํ•œํ•œ ์ผ๋ จ์˜ ์ž์‹ ์˜ ์‹ ํ˜ธ ์‚ฌ์ด์— N ์ดˆ์˜ ์ง€์—ฐ์„ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

ํƒ€์ด๋จธ๋Š” ์‚ฌ์šฉ์ž์˜ ๋ช…๋ น์œผ๋กœ ์ข…๋ฃŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์žฌ๊ท€์™€ ๊ด€๋ จํ•˜์—ฌ ๋‚ด CS๊ฐ€ ๋…น์Šฌ ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฒฐ๊ตญ ์Šคํƒ ํ”„๋ ˆ์ž„ ์˜ค๋ฒ„ํ”Œ๋กœ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„๊นŒ์š”?

@eimantas ์•„๋‹ˆ์š”, ์ง€์—ฐ์ด ๋™ ๊ธฐ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. RAC๋Š” ํ”„๋ ˆ์ž„์„ ๋– ๋‚˜ ์ง€์—ฐ์ด ๊ฒฝ๊ณผ ํ•œ ํ›„ ๋‚˜์ค‘์— ์ฝ”๋“œ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค.

์ฃ„์†ก ํ•ฉ๋‹ˆ๋‹ค๋งŒ, ์—ฌ์ „ํžˆ ๊ท€ํ•˜์˜ ์•„์ด๋””์–ด๋ฅผ ์–ป์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. (๊ตฌ์ฒด์ ์œผ๋กœ concat:[RACSignal delay:N] ์ „ํ™”ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

- (RACSignal *)doStuffRepeatedly {
    return [[[RACSignal
        defer:^{
            // Do some stuff here
            return [RACSignal empty];
        }]
        // Wait 5 seconds
        concat:[RACSignal delay:5]]
        then:^{
            // Do more stuff
            return [self doStuffRepeatedly];
        }];
}

ํ™œ๋™์ด ์—†์–ด์„œ ๋‹ซ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰