From 0a89cf3896830cdeade2bef5e932b2dc07a53cbf Mon Sep 17 00:00:00 2001 From: cognitiveflux Date: Thu, 2 Oct 2014 17:20:42 -0700 Subject: [PATCH] Updated CLLocationManagerDelegate methods for location update *Changed locationManager:didUpdateToLocation:fromLocation to locationManager:didUpdateLocations. *Preserved callback result[:from] key-value by storing previous location in an instance variable. *Added result[:previous] to include additional locations returned by the delegate method. *Updated inline documentation for location.rb *Updated spec BW::Location --- README.md | 4 +++ motion/location/location.rb | 18 +++++++--- spec/motion/location/location_spec.rb | 47 ++++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 290336d8..30162a00 100644 --- a/README.md +++ b/README.md @@ -419,6 +419,10 @@ BW::Location.get(purpose: 'We need to use your GPS because...') do |result| p "To Lat #{result[:to].latitude}, Long #{result[:to].longitude}" end ``` +*Note: `result[:from]` will return `nil` the first time location services are started.* + +The `:previous` key in the `BW::Location.get()` result hash will always return an array of zero or more additional `CLLocation` objects aside from the locations returned from the `:to` and `:from` hash keys. While in most scenarios this array will be empty, per [Apple's Documentation](https://developer.apple.com/library/IOs/documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/index.html#//apple_ref/occ/intfm/CLLocationManagerDelegate/locationManager:didUpdateLocations:) if there are deferred updates or multiple locations that arrived before they could be delivered, multiple locations will be returned in an order of oldest to newest. + ```ruby BW::Location.get_compass do |result| diff --git a/motion/location/location.rb b/motion/location/location.rb index d4f3389d..be64fee5 100644 --- a/motion/location/location.rb +++ b/motion/location/location.rb @@ -47,12 +47,15 @@ module Error # } # @block for callback. takes one argument, `result`. # - On error or cancelled, is called with a hash {error: BW::Location::Error::} - # - On success, is called with a hash {to: #, from: #} + # - On success, is called with a hash {to: #, from: #, previous: [#,...]} + # -- :previous will return an Array of CLLocation objects, ordered from oldest to newest, excluding the + # locations :to and :from, returning an empty Array if no additional locations were provided # # Example # BW::Location.get(distance_filter: 10, desired_accuracy: :nearest_ten_meters) do |result| # result[:to].class == CLLocation # result[:from].class == CLLocation + # result[:previous].class == NSArray # p "Lat #{result[:to].latitude}, Long #{result[:to].longitude}" # end def get(options = {}, &block) @@ -70,6 +73,7 @@ def get(options = {}, &block) @options[:significant] = false if @options[:significant].nil? @retries = 0 + @from_location = nil if not enabled? error(Error::DISABLED) and return @@ -172,13 +176,19 @@ def error(type) ########## # CLLocationManagerDelegate Methods - def locationManager(manager, didUpdateToLocation:newLocation, fromLocation:oldLocation) + def locationManager(manager, didUpdateLocations:locations) if @options[:once] - @callback && @callback.call(newLocation) + @callback && @callback.call(locations.last) @callback = proc { |result| } stop else - @callback && @callback.call({to: newLocation, from: oldLocation}) + size = locations.count + result = {to: locations.last, + from: ( (size > 1) ? locations.last(2).first : @from_location ), + previous: ( (size > 2) ? locations.first(size - 2) : [] ) + } + @from_location = result[:to] + @callback && @callback.call(result) end end diff --git a/spec/motion/location/location_spec.rb b/spec/motion/location/location_spec.rb index dc688b24..8c28e526 100644 --- a/spec/motion/location/location_spec.rb +++ b/spec/motion/location/location_spec.rb @@ -147,7 +147,7 @@ def reset result[:from].longitude.should == 49 end - BW::Location.locationManager(location_manager, didUpdateToLocation: to, fromLocation: from) + BW::Location.locationManager(location_manager, didUpdateLocations: [from, to]) end end @@ -163,11 +163,11 @@ def reset @number_times += 1 end - BW::Location.locationManager(location_manager, didUpdateToLocation: to, fromLocation: from) + BW::Location.locationManager(location_manager, didUpdateLocations: [from, to]) to = CLLocation.alloc.initWithLatitude(0, longitude: 0) from = CLLocation.alloc.initWithLatitude(0, longitude: 0) - BW::Location.locationManager(location_manager, didUpdateToLocation: to, fromLocation: from) + BW::Location.locationManager(location_manager, didUpdateLocations: [from, to]) @number_times.should == 1 end end @@ -233,7 +233,46 @@ def reset result[:from].longitude.should == 49 end - BW::Location.locationManager(location_manager, didUpdateToLocation: to, fromLocation: from) + BW::Location.locationManager(location_manager, didUpdateLocations: [from, to]) + end + + it "should include previous locations" do + to = CLLocation.alloc.initWithLatitude(100, longitude: 50) + from = CLLocation.alloc.initWithLatitude(100, longitude: 49) + previous = CLLocation.alloc.initWithLatitude(100, longitude: 48) + + BW::Location.get_significant do |result| + result[:to].longitude.should == 50 + result[:from].longitude.should == 49 + result[:previous].last.longitude.should == 48 + end + + BW::Location.locationManager(location_manager, didUpdateLocations: [previous, from, to]) + end + + it "should preserve previous location when delegate method only returns current location" do + to = CLLocation.alloc.initWithLatitude(100, longitude: 49) + + @number_times = 0 + BW::Location.get_significant do |result| + if @number_times == 0 + result[:to].longitude.should == 49 + result[:from].should == nil + result[:previous].last.should == nil + else + result[:to].longitude.should == 50 + result[:from].longitude.should == 49 + result[:previous].last.should == nil + end + @number_times += 1 + end + + BW::Location.locationManager(location_manager, didUpdateLocations: [to]) + + to = CLLocation.alloc.initWithLatitude(100, longitude: 50) + BW::Location.locationManager(location_manager, didUpdateLocations: [to]) + + @number_times.should == 2 end end