Добър въпрос! Обикновено бихте използвали 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:
се извиква всеки път, когато се добави нов абонат към върнатия сигнал. Когато това се случи:
- Проверяваме дали броят на абонатите в момента е нула. Ако е така, току-що добавеният абонат е първият, така че трябва да активираме (или да активираме отново) актуализациите на местоположението.
- Ние свързваме абоната директно към нашия
locationSubject
, така че стойностите от последния автоматично се подават в първия.
- След това, в някой бъдещ момент, когато абонаментът е изхвърляне, ние намаляваме броя и спираме актуализациите на местоположението, ако е необходимо.
Сега всичко, което остава, е да се абонирате за 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
по-горе, но това поведение беше променено защото прави страничните ефекти изключително непредвидими. Този случай на използване трябва да е безопасен, но има и други моменти (като когато правите мрежова заявка или изпълнявате команда на shell), когато автоматичното повторно свързване би било ужасно.
person
Justin Spahr-Summers
schedule
08.02.2013