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.
Related
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]
I am new to WinRT and was playing around with session state. I am navigating to a page to collect data and then want to return to the main page. Just before navigation I am using:
SuspensionManager.SessionState["CurrentState"] = someObject;
The object contains lists of other mildly complex objects, etc... All seems to be working but is this the correct way to use the Suspension Manager?
I have looked at other posts on the topic and some people report that it is necessary to use [DataContract] and [DataMember] attributes to all the classes that are serialized. I omitted them and it still works, (getting the data across pages). So what is the recommended approach?
I may be reading too much into one aspect your question, but the role of SuspensionManager and SessionState is to store just enough information to bring your application back to the place the user left it if the application is actually terminated while it's suspended.
In the Windows 8 application lifecycle, your app gets 'suspended' if another app comes to the foreground. While your app is suspended all of its state is retained in memory, and if reactivated (you flip back to it) everything* is restored "for free".
A suspended app could, however, also be terminated by the OS (b/c of memory pressure, for instance) and there is no opportunity to react to that scenario in your app, so what you are really doing with SessionState is storing what's necessary to 'recreate' the last place the user was at IF the application had actually terminated. It's essentially an insurance policy: if the application is merely suspended, SessionState isn't really needed.
The 'what's necessary' is the grey area, I could store all of the information about say a user profile that was in progress OR I could save just the userid that indexes into my persistent storage of all the user profile data. I generally have more of a minimalist view and will retain as little as possible in SessionState - I make the analogy that I don't need to remember everything, I only need to remember how/where to get/find everything.
There's an implication as well in your question that you're using SessionState to pass information between pages in your app, and that's not really the intent. Each page of your app is typically connected with a view model, and when you interact with a page of that app, you'd update the view model and drive additional screens and experiences from the changes already in the view model. Leaving one screen of your app and returning the main one would also imply to me that you've persisted what ever information you collected - certainly to the view model, but also to something persistent like a data base or local storage. When you revisit that page, you'd then pull the data back out of your view model (or that persistent storage); the main page doesn't need that information so why hold on to it?
Lastly, since you mentioned being new to WinRT, you may want to check out App Builder, which pulls together a number of resources in consumable chunks to lead you through building an app over a period of 30-days (though all material is available, so you can consume at any pace you want :)) The discussion of lifecycle management that's germane to your question comes in on Day 17 of that sequence.
*"everything is restored for free" doesn't necessarily mean you don't have any work to do when an app comes out of the suspended state. There may be stale data that requires refreshing, and connections or other transient or short-lived entities may need to be refreshed/recreated.
Most of the time devs are asking how to filter old cached locations, however I'm interested in opposite thing - how to preserve and get old location :) Here's my case: I have weather screen in my app where I'm downloading weather forecasts for current location. As soon as the app starts, I'm starting standard location updates with 1km accuracy and saving received location in my locator class private member. If the app does not receive any location update then it needs to show any known previous location - like grabbing one out of [CLLocationManager location].
The problem is with iPad2. My app runs without device restart for about a week but [CLLocationManager location] returns nil very frequently. For example, I have opened google maps app yesterday on iPad and got the message "Cannot determine location", and so [CLLocationManager location] returned nil in my app. Then I pressed location arrow icon in google maps app and then google maps app showed my current place. Also, [CLLocationManager location] returned some location in my app. However, the same problem persist today - [CLLocationManager location] returns nil again, so I guess CLLocationManager discards location cache after some time and if you are not moving with device then you will not get any known previous location. Any ideas how to workaround this and to force CLLocationManager to retrieve any location if it's nil?
Documentation
The most recently retrieved user location. (read-only)
#property(readonly, nonatomic) CLLocation *location
Discussion
The value of this property is nil if no location data has ever been retrieved.
In iOS 4.0 and later, this property may contain a more recent location object at launch time. Specifically, if significant location updates are running and your application is terminated, this property is updated with the most recent location data when your application is relaunched (and you create a new location manager object). This location data may be more recent than the last location event processed by your application.
It is always a good idea to check the timestamp of the location stored in this property. 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.
It will store it in the cache for as long as possible, there isn't a timeout on it. It may set it to nil if something that used location services failed to get any location.
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?
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.