我对ReactiveCocoa框架及其潜力感到非常兴奋,所以我决定我会咬紧牙关并使用它编写我的第一个应用程序。 在我的应用程序中,我已经编写了各种服务和代理,但我现在需要'Reactive-Cocoa-ise',以便我可以继续使用实际的GUI方面。
那就是说,为了让我更好地理解这一点,我正在编写一些简单的代码来尝试概念。 在这种情况下,为CLLocationManagerDelegate编写一个包装器。
在实际应用中,用例如下:
startMonitoringSignificantLocationChanges
,locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
),然后我们stopMonitoringSignificantLocationChanges
您可以在https://github.com/ippoippo/reactive-core-location-test
看到测试工具线束“起作用”,它起飞并取出位置。但是,我真的很担心我是以正确的方式做到这一点。
考虑这段代码
RACSignal *fetchLocationSignal = [lmDelegate latestLocationSignal];
RACSignal *locationSignal = [fetchLocationSignal catch:^RACSignal *(NSError *error) {
NSLog(@"Unable to fetch location, going to grab default instead: %@", error);
CLLocation *defaultLocation = [lmDelegate defaultLocation];
NSLog(@"defaultLocation = [%@]", defaultLocation);
// TODO OK, so now what. I just want to handle the error and
// pass back this default location as if nothing went wrong???
return [RACSignal empty];
}];
NSLog(@"Created signal, about to bind on self.locationLabel text");
RAC(self.locationLabel, text) = [[locationSignal filter:^BOOL(CLLocation *newLocation) {
NSLog(@"Doing filter first, newLocation = [%@]", newLocation);
return newLocation != nil;
}] map:^(CLLocation *newLocation) {
NSLog(@"Going to return the coordinates in map function");
return [NSString stringWithFormat:@"%d, %d", newLocation.coordinate.longitude, newLocation.coordinate.latitude];
}];
catch
然后让我有机会向代表询问默认位置。但是,我然后坚持如何将该默认位置作为信号传回?或者我只是更改defaultLocation
方法以返回RACSignal
而不是CLLocation
?? sendNext
完成?目前它被编码为sendCompleted
,但似乎可以像sendNext
那样完成。 sendCompleted
中的代码移动到init方法中呢?为漫无边际的问题道歉,似乎只是在我的脑海里乱转。
答案 0 :(得分:3)
如何处理错误?我可以使用catch,然后让我有机会向代表询问默认位置。
你所以关闭。使用+[RACSignal return:]
创建一个仅发送默认位置的信号:
RACSignal *locationSignal = [fetchLocationSignal catch:^RACSignal *(NSError *error) {
NSLog(@"Unable to fetch location, going to grab default instead: %@", error);
CLLocation *defaultLocation = [lmDelegate defaultLocation];
NSLog(@"defaultLocation = [%@]", defaultLocation);
return [RACSignal return:defaultLocation];
}];
当我返回该位置时,是应该以sendNext还是sendCompleted完成?目前它被编码为sendNext,但似乎可以像sendCompleted那样完成。
为了实际发送数据,您需要使用-sendNext:
。如果这是信号发送的唯一内容,那么它之后也应该-sendCompleted
。但是,如果它随着准确度的提高或位置的变化而继续发送位置,那么它就不应该完成。
更一般地说,信号可以发送任意数量的next
s(0 *),但只能完成或错误。一旦发送完成或错误,信号就完成了。它不会再发送任何值。
实际上,答案取决于我如何创建委托。每次加载视图时,此测试应用程序都会创建一个新的Delegate。这是我应该做的事情,我应该让代表成为单身人士。如果它是单身,那么sendNext似乎是正确的做法。但是,如果那意味着我将我在委托中的latestLocationSignal中的代码移动到init方法中呢?
我不确定我是否有足够的上下文来回答这个问题,除了说单身人士永远不是答案;)每次加载视图时创建一个新的委托似乎对我来说是合理的。
很难回答这样的广泛问题,因为我几乎不了解你的设计。希望这些答案有所帮助。如果您需要更多说明,具体示例确实很有帮助。
答案 1 :(得分:2)
在ReactiveCocoa 3.0和swift中似乎非常容易:
import ReactiveCocoa
import LlamaKit
class SignalCollector: NSObject, CLLocationManagerDelegate {
let (signal,sink) = Signal<CLLocation, NoError>.pipe()
let locationManager = CLLocationManager()
func start(){
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
for item in locations {
if let location = item as? CLLocation {
sink.put(Event.Next(Box(location))
}
}
}
}
无论您何时需要收听位置事件,请与观察者一起使用信号:
var locationSignals : [CLLocation] = []
signal.observe(next: { value in locationSignals.append(value)})
请注意,由于此时语法可能会发生变化,因此它会预先发布。
答案 2 :(得分:2)
将上面的答案更新为ReactiveCocoa 4和Swift 2.1:
import Foundation
import ReactiveCocoa
class SignalCollector: NSObject, CLLocationManagerDelegate {
let (signal,sink) = Signal<CLLocation, NoError>.pipe()
let locationManager = CLLocationManager()
func start(){
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for item in locations {
guard let location = item as CLLocation! else { return }
sink.sendNext(location)
}
}
倾听事件:
var locationSignals : [CLLocation] = []
signal.observeNext({ newLocation in
locationSignals.append(newLocation)
})