6

RACSignalサブスクライバーがいない場合は公開を停止し、サブスクライバーがいる場合は自動開始するを実装するにはどうすればよいですか?

シナリオは次のとおりです。

currentLocationSignalにがあるとしましょうAppDelegateLocationViewControllerビューがロードされるときにサブスクライブし、currentLocationSignalビューがアンロードされるときにサブスクライブを解除(破棄)します。現在地を取得するのに数秒かかるのでcurrentLocationSignal、アプリが開いたときに常にサブスクライブしたいので(そして数秒後に自動登録解除)、到着するまでLocationViewControllerに正確な位置を取得します。したがって、信号には複数のサブスクライバーが存在する可能性があります。最初のサブスクライバーがリッスンするときは呼び出しを開始する必要startUpdatingLocationがあり、サブスクライバーがいないときは呼び出す必要がありますstopUpdatingLocation

4

1 に答える 1

6

良い質問!通常、このようなユースケースにはRACMulticastConnectionを使用しますが、信号を後で再アクティブ化できるようにするため接続だけでは適していません。

おそらく最も簡単な答えは、接続がどのように機能するかを模倣することですが、必要な特定の動作を備えています。基本的に、特定の時点でのサブスクライバーの数を追跡し、その数に基づいて場所の更新を開始/停止します。

locationSubjectプロパティを追加することから始めましょう。新しいサブスクライバーには常に最新の送信場所をすぐに取得してもらいたいため、サブジェクトはRACReplaySubjectである必要があります。その件名で更新を実装するのは簡単です。

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    [self.locationSubject sendNext:locations.lastObject];
}

次に、購読者数を追跡して増減するシグナルを実装します。これは、numberOfLocationSubscribers整数プロパティを使用して機能します。

- (RACSignal *)currentLocationSignal {
    return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        @synchronized (self) {
            if (self.numberOfLocationSubscribers == 0) {
                [self.locationManager startUpdatingLocation];
            }

            ++self.numberOfLocationSubscribers;
        }

        [self.locationSubject subscribe:subscriber];

        return [RACDisposable disposableWithBlock:^{
            @synchronized (self) {
                --self.numberOfLocationSubscribers;
                if (self.numberOfLocationSubscribers == 0) {
                    [self.locationManager stopUpdatingLocation];
                }
            }
        }];
    }];
}

上記のコードでは+createSignal:、返されたシグナルに新しいサブスクライバーが追加されるたびに、ブロックが呼び出されます。その場合:

  1. サブスクライバーの数が現在ゼロであるかどうかを確認します。その場合、追加したばかりのサブスクライバーが最初のサブスクライバーであるため、位置情報の更新を有効にする (または再度有効にする) 必要があります。
  2. サブスクライバーを に直接フックするlocationSubjectため、後者からの値は自動的に前者に供給されます。
  3. その後、サブスクリプションが破棄された時点でカウントを減らし、必要に応じて位置情報の更新を停止します。

あとは、起動時にサブスクライブしcurrentLocationSignal、数秒後に自動的にサブスクライブを解除するだけです。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Use a capacity of 1 because we only ever care about the latest
    // location.
    self.locationSubject = [RACReplaySubject replaySubjectWithCapacity:1];

    [[self.currentLocationSignal
        takeUntil:[RACSignal interval:3]]
        subscribeCompleted:^{
            // We don't actually need to do anything here, but we need
            // a subscription to keep the location updating going for the
            // time specified.
        }];

    return YES;
}

これはすぐにサブスクライブし、シグナルが最初の値を送信しself.currentLocationSignalたときにそのサブスクリプションを自動的に破棄します。+interval:

興味深いことに、-[RACMulticastConnection autoconnect] 以前-currentLocationSignalは上記のように動作していましたが、副作用が非常に予測不可能になるため、動作が変更されました。このユース ケースは安全なはずですが、自動再接続が恐ろしい場合もあります (ネットワーク リクエストを行うときやシェル コマンドを実行するときなど)。

于 2013-02-08T17:26:44.297 に答える