CoreLocation Framework: Does locationManager send a message with filled in parameters everytime it logs a new location? - objective-c

In the process of learning iOS development and I am currently being taught how to use the core location framework.
I'm told that we need to create an instance of CLLocationManager, and then set a delegate, then implement this method:
-(void) locationManager: (CLLocationManager*)manager
didUpdateToLocation: (CLLocation*)newLocation
fromLocation: (CLLocation*)oldLocation
The book doesn't thoroughly explain how the location is actually received. From what I'm understanding, whenever locationManager logs a new location, it then sends a message (to the delegate?) with the selector being the above method, filling the parameters with the location data? Then we must implement this method and choose what to do with these parameters.
Is this correct? and if not, could someone explain to me exactly what is going on?
Thanks in advance, this is confusing me a ton.

Right, although the message you should implement starting in iOS 6 is -locationManager:didUpdateLocations:. After setting up the delegate, call -startUpdatingLocation and the Location Manager will start sending -locationManager:didUpdateLocations: (or the other method) whenever the location changes until you tell it to stop. Your implementation of that method an do whatever you like -- update a position on a map, log the location to a file, look up the nearest gas stations... There's some reason that you're asking for location updates, and whatever that reason is, this lets you do it.

Related

Getting user's location once, and only once

My app needs to know the rough location of a user, with a resolution of their state/province. This way we know what the default tax rate should be in a simple tax calculator. They can still pick it after that, but its always nice to try to get it right.
Is there an easy way to get this sort of resolution without all the rigamarole of callbacks and such? I don't need updates, a single rough location will do, and an old one is likely perfectly fine.
There are no short simple ways to get current location.
That means that you need init CLLocationManager object, call startUpdatingLocation method and retrieve result in delegate method.
It's impossible to get current location synchronously by using one line of code because retrieving location info could take much time (For example turning on GPS sensor and so on.). That's why you get info by asynchronous delegate methods.
is the only way,
but to get a single user position
within the method locationManager:didUpdateLocations: call stopUpdateLocation:
[locationManager stopUpdatingLocation]

Should I send [locationManager stopUpdatingLocation] in locationManager:didFailWithError:?

My app uses the typical pattern of starting a CLLocationManager and then calling stopUpdatingLocation from locationManager:didUpdateToLocation:fromLocation: if the newLocation is accurate enough. My question is whether I also need to call
[locationManager stopUpdatingLocation];
in locationManager:didFailWithError:. The Apple docs say
If the location service is unable to retrieve a location right away, it reports a kCLErrorLocationUnknown error and keeps trying. In such a situation, you can simply ignore the error and wait for a new event.
If the user denies your application’s use of the location service, this method reports a kCLErrorDenied error. Upon receiving such an error, you should stop the location service.
In the former case I shouldn’t call stopUpdatingLocation, since the location manager may still emit a good location. What about the other cases? My app always checks [CLLocationManager locationServicesEnabled] and [CLLocationManager authorizationStatus] before trying to use location services, so do I really need to handle the kCLErrorDenied case? And in the event of any other error, will location services be stopped automatically?
First off I think you should handle most error cases. Especially if it's as easy to handle as this one. ;-)
What happens if the user has granted access and uses your app. While the app is running she multitasks and changes into settings.app to disable location services; either generally or specifically for your app. Then you already checked for authorization and use location updates, but suddenly you aren't authorized anymore. I guess that's exactly the case you are asking about, right?

Core Data NSManagedObject - tracking if attribute was changed

I have an object - Config. I want to know if the Account attribute on Config has changed. When this happens, I want to send a NSNotification so that all code that cares about when the Account changes will know. My initial thought was in my NSManagedObject subclass that I would override the setAccount method to set a transient attribute AccountDidChange to true. Then in didSave if AccountDidChange was true I would send the notification and then set it back to false. Is there a better way? My issue though is that from what I've read, by changing AccountDidChange back to false, I would have dirtied my object and need to save again.
A little more info:
The Config object is the current configuration of the application. Account could actually be changed to ActiveAccount. There is a relationship to the Account Entity that has a list of all Accounts. The idea is that the user can change the active account of the application. So we have a set of servers and the user can only be logged into one at a time. Config.Account points to that active account and it is used to setup connections to the server to retrieve information. I am using this notification that Config.Account has changed to tell other objects to clean up their information - like list of alerts. Basically, all information is per Account so it needs to be removed and then refetched on its next load with the new active account.
Also, the given names are not my actual object names - just trying to make the example easier to follow.
Take a look at KVO (Key-Value Observing): Key-Value Observing Programming Guide. That's the standard way to do this in Cocoa, and is a fundamental technology that you need to understand to be a good Cocoa programmer.
KVO will let objects that care about changes to the Account property (which you should probably name account, not Account) register to be notified when the property is changed. KVO will "just work" for standard NSManagedObjects, without any additional work on your part.
The relevant methods are as follows:
-addObserver:forKeyPath:options:context: which you call on your Config object to set up the observation
-observeValueForKeyPath:ofObject:change:context: which will be called on the observer object anytime an observed value is changed
-removeObserver:forKeyPath: which you need to make sure you call when the observer no longer needs change notifications (including before the observer is deallocated).
This is all described in a lot more detail in the linked documentation.
EDIT BELOW:
Without knowing anything about your application, it's hard to know why you'd want to be notified only upon save. NSManagedObjectContext posts NSManagedObjectContextWillSaveNotification and NSManagedObjectContextDidSaveNotification. The notification's userInfo has arrays containing inserted, updated and deleted objects, but the notifications aren't as fine-grained as individual properties. I suppose you could manually keep track of changed accounts between didSave notifications. That'll probably get inefficient if you have lots of Configs in your store.
Changes to NSManagedObjects are immediate, they're just not saved to the persistent store until you call save: on the managed object context. Perhaps if you explain more about exactly what you're trying to accomplish and why, I can better help.

CLLocationManager initialization

I'm working on a web application that enables users to login, only at specific locations. I'm using CLLocationManager and I initialized and called startUpdatingLocation at AppDelegate -didFinishLaunchingWithOptions. My UIWebView is supposed to pull the location at initialization to determine whether user's within the specified locations. However, at the launch of my application, [locationManager location] is always null and updates after my UIWebView is initialized and displayed therefore already sending an error message to the user.
How do I make my locationManager update its location at initialization?
Sounds like you've coded the location stuff correctly. What you are missing (but have seen) is that the update most certainly does not happen instantaneously. You need to "gate" the rest of your UI's presentation (i.e. your webview) on the location information becoming available. There are a lot of ways to do this. A common tactic is to present a full-screen "HUD" or veil with some indicator to the user that the app is initializing or locating them (with an activity indicator, too, is always a nice touch.) Behind that (out of sight to the user) you can be waiting for the location result and then kickoff the appropriate UI update, and then drop the veil.
Any of that make sense or give you some ideas? I've done this plenty of times. Synchronizing async activities (like location updates) with real-time UI updates that make sense can be challenging, but isn't impossible. :-)
You will need to account for an initial nil value in your applications UI and wait for the first location update.
-location
Discussion
The value of this property is nil if no location data has
ever been retrieved.
It is a good idea to check the timestamp of the location that is
returned. If the receiver is currently gathering location data, but
the minimum distance filter is large, the returned location might be
relatively old. If it is, you can stop the receiver and start it again
to force an update
Also you should check out Region Monitoring since you would like for you users to only be able to login at specific locations.

Media Foundation: another way to call IMFActivate::ShutdownObject?

Here is a question about IMFActivate::ActivateObject and IMFActivate::ShutdownObject in Media Foundation.
According to MSDN, the component that calls ActivateObject is responsible for calling ShutdownObject.
But there are two examples not following this rule:
http://msdn.microsoft.com/en-us/library/dd388503%28VS.85%29.aspx
and
http://msdn.microsoft.com/en-us/library/dd317912%28VS.85%29.aspx
In these two examples, they call ActivateObject and then release IMFActivate interface without calling ShutdownObject method.
This is going to lead to memory leaking, right? Or there is another way to release the resource occupied by the object?
(Can I use IMFMediaSource::Shutdown to release the object instead of using IMFActivate::ShutdownObject)
Thanks in advance.
You're right that you're supposed to call IMFActivate::ShutdownObject when you're done using the object you activated. However, notice that the sample in question is instantiating an IMFMediaSource to be returned in an out param.
HRESULT CreateVideoDeviceSource(IMFMediaSource **ppSource)
If CreateVideoDeviceSource were to do a ShutdownObject on the IMFMediaSource it instantiated and then hand it back to you, it would be in a shut-down state and therefore probably unusable.
To answer your question about what you're supposed to do about this, you can probably get away with a pMyMediaSource->Shutdown() after you're all done using it.
More info: IMFActivate's other use in Media Foundation is for allowing an MF object to be instantiated in a different process (useful because the MF Media Session will play DRM-protected content in a separate process); in that case, the MF Media Session will indeed call IMFActivate::ShutdownObject on any IMFActivates you gave it.