Say you are doing something critical to the app's usability at startup (like copying the SQLite DB or setting up CoreData) and something goes wrong that doesn't cause a crash but you don't want the user to continue. What can you do?
Currently my app has abort() and NSAssert(false,...) calls to make sure the app doesn't continue, obviously after the error has been logged. But somehow I think its not going to score points with Apple on the app store.
Anyone have any ideas what I can do in such situations? I understand for instance that if there is no connectivity you can put your app in 'offline' mode but lets say the DB couldn't be properly setup (for argument sake). There is no 'offline' for that and so the user cannot continue. The user needs to quit the app and try again or report the problem. Wouldn't you agree, or am I missing something?
I just decided to create a view that has a message on it explaining to the user that a critical error has occurred and explained some steps to follow to resolve it. It prevents the user from using the app until it is resolved. So if the DB is missing or the model schema doesn't match the DB schema it will bring up that view.
Its one way of doing it that I took. If anyone has a different way, I'd like to hear it.
Related
I'm working in an application that loads a few remote jsons at startup. The application has been programmed to do certain tests on the incoming data to prevent invalid states and to detect possible human errors. However, I am not sure of how we should treat such situation at the GUI level - our initial idea was to display a "Oops there was an unexpected server error. We are working to solve this issue. Please, try again later." popup to quit the application when the user hits an "Ok" or "Exit" button.
Apple apparently discourages exiting the application from within your code: https://developer.apple.com/library/ios/#qa/qa2008/qa1561.html
What good alternatives are there to handle this situation?
Update: I updated the error message above, since it was misleading.
I encountered a similar issue. My app was useless unless it could establish a connection to a server.
There are two ways around this:
place holder text, this can hold the position until you can get your json arrays, or at least allow a back drop for popping an alert.
Load a view with all interaction disabled, with a small message box saying "connecting..."
Basically I have taken the first responding storyboard frame and disabled everything that the user could touch. I just allowed static interaction like pressing a button to get to the about screen.
Don't beat yourself up too much about it though. If you don't have any connectivity at all then none of the user's apps are going to be functioning properly. I think in this state, from a GUI perspective it is mostly about damage control and protecting the user experience.
It's tough to be graceful at startup. I suggest presenting UI modally while your app gets ready to run. I asked and answered this SO question which shows a clean way to do the UI, including nice transition effects.
As for exiting: Your app should never self-terminate (copyright Arnold Schwartzenegger circa 2003). The correct app behavior when it can't get something done that has to be done modally is to alert the user and give the option to retry. If the user wants to not retry, there's a hardware home button on the phone.
This is a rather general question, as I don't have any solid evidence atm.
I have an iPhone app with about 20,000 users. It allows users to message each other, and saves those messages in core data. The only other thing it saves in core data is the users profile, a copy locally and a copy on the server.
I have a small percentage of users complaining that they receive messages but nothing shows, when they send a message (which immediately goes into core data then shows on screen) it disappears immediately. Nothing but a full restore seems to fix it, and from what I can gather, even a restore which involves them restoring a backup they just made doesn't fix it.
My first thought was that core data must have become corrupted in some way ... but the messages they attempt to send actually do send, and this would be impossible if their local profile had become corrupted too.
I've never been able to recreate it, or found anyone face to face who has had a similar problem.
Does anyone have any suggestions on what could occur in core data that could lead to a situation like this so I can start to try and track down the problem? I'd estimate it's happening with about 1% of users.
Once again, sorry for the generality of the question, but it's all I have to work with just now!
Thanks
** Edit
Just to clarify, deleting the app and reinstalling it, does not fix the problem when this happens.
** Edit
I just had some more information from a user who is suffering from the problem ... the information my app saved in core data still exists after the app has been deleted and re-installed, all of it. I have deleted and re-installed my app hundreds of times over the last year, on countless different devices, and every time I delete and re-install, all previous data stored in core data is completely erased .. yet for these users, this is not happening. Does this sound like an iPhone issue that basically requires a restore?
** Edit 03/12/2010
AT LAST! I have some real solid information to work on. I added flurry to my latest release so I could track any core data error messages, and was able to correlate the errors received with a user id that I knew for a fact was experiencing the problem ...
The error is: "Msg: Error Domain=NSCocoaErrorDomain Code=133020 'The operation couldn’t be completed. (Cocoa error 133020.)' UserInfo=0x39c7c0 {conflictList=( 'NSMergeConflict (0x39c700) for NSManagedObject (0x38ad00) with objectID '0x375c30
Unfortunately, the error is trimmed. Flurry must have limit on the size of the message it can pass.
I don't have access to my mac and code just now, I'll start investigating as soon as I do and post back with some source code and any findings I have.
I'm having a problem like that right now. So far I have figured out that the same object is modified in two NSManagedObjectContext-s. The object X has (at least) two persistent attribites, a and b, one thread changes a, another thread changes b, and CoreData cannot merge.
The key phrase in the error message is NSMergeConflict:
Error Domain=NSCocoaErrorDomain Code=133020 "The operation couldn’t be completed. (Cocoa error 133020.)" UserInfo=0x1544c7d0 {conflictList=(
"NSMergeConflict (0xc489f40) for NSManagedObject (0xd833ca0) with objectID '0xd82b7c...
Not sure this really helps, but at least it tells you what might go wrong...
Does anyone have any suggestions on what could occur in core data that could lead to a situation like this so I can start to try and track down the problem?
About a zillion different things.
Your real problem is that you are trying to debug in a speculative fashion. To properly fix this bug, you first need to know how to reproduce the bug. There's no other way to know if you've fixed it after you've tried something.
I would not start by blaming the underlying frameworks like Core Data. Odds are your program is the one losing the data. Start with that assumption.
Does it affect these users from the moment they set up there account? Could it be something to do with their username/id/personal information?
If deleting the app completely and reinstalling doesn't solve the problem, then I'm at a loss for how it could be core data - as you yourself say, I often do this and it removes all core data each time. So if it is core data corruption, it would have to be in your construction of the core data instead of the database itself. I don't think it likely that only people who install your app would have problems with core-data being retained.
If you have contact with a user experiencing this problem, I would get them to try to create a new username that is "safe and normal".
Good Luck.
I've decided to integrate OpenFeint into my new game to have achievements and leaderboards.
The game is dynamic and I would like user to be rewarded immediately for some successful results, but as it seems for me, OpenFeint's achievements are a bit sluggish and it shows visual notification only when it receives confirmation from the server.
Is it possible to change something in settings or hack it a little bit to show notification immediately as soon as it checks only local database if the achievement has not been unlocked it?
Not sure if this relates to the Android version of the SDK (which seems even slower), but we couldn't figure out how to make it faster. It was so unacceptably slow that we started developing our own framework that fixes most of open feint's shortcomings and then some. Check out Swarm, it might fit your needs better.
There are several things you can do to more tightly control the timing of these notifications. I'll explain one approach and you can use this as a starting point to explore further on your own. These suggestions apply specifically to iOS apps. One caveat is that these suggestions refer to internal APIs in OFSDK 2.8 for iOS and not ordinarily recommended for high level use and subject to change in future versions.
The first thing I recommend is that you build the sample app with your own product key. Use the standard sample app to experiment before applying the result to your own code.
You are going to get the snappiest response by separating the notification pop-up UI from the process of submitting the achievement. This way you don't have to worry about getting wrapped up in the logic for deciding whether the submission is going just to the local db or is doing the full confirmation on an async network transaction.
See the declaration of "showAchievementNotice" in "OFNotification.h". Performing a search in the sample app, you will see that this is the internal API used for displaying the achievement pop-up when an achievement is earned. It does not actually submit the achievement. You can call this method directly as it is called from "OFAchievementService.mm" to directly control when the message appears. You can then use the following article to disable the pop-up from being called when the actual submission occurs:
http://support.openfeint.com/dev/notification-pop-ups-in-ios/
This gives you complete freedom to call the submission at a later time provided you keep track of the need to do so. For example, you could locally serialize a flag to take care of the actual submission either after the level is done or the next time the app starts up. Don't forget that the user could quit out of a game without cleanly finishing a level.
how to handle error in an iphone app ?
log and exit ? show an alert dialog and exit ?
for exemple, if an image is missing from the bundle..even though it should not ...
You are never supposed to exit the app programmatically. Advise the user there was a problem, offer to try it again, etc. But don't kill the app. This is explicit in the Apple HIG.
Let the user decide your app needs exiting. Don't do it for them.
Ideally, don't get yourself in this situation. : ) Easier said than done I know.
#Genericrich has it pretty spot on:
Advise the user there was a problem, offer to try it again, etc. But don't kill the app. This is explicit in the Apple HIG.
The only advice I would add is to expect the unexpected. Just make sure your app is ready for those little blowups. This might be things like: default information to fill in the blanks, adequate alerts to let users know what's happening/retry, saving state before attempting failure prone destructive actions, and any other defensive programming habits you can think of.
As an added note if you are wanting to test network errors you may want to check out Craig Hockenberry's excellent post Slow ride, make it easy on the subject.
Alert box and exit should be fine. Short and sweet with just enough communication with the user to let them know why your software is about to not work.
I have an application that allows you to edit some percentages, however it will only let you commit those changes if the percentages add up to 100. However because the Core Data template includes the save code in the application will terminate. If the user changed something and then exited the application, the item would be of course saved even though it did not add to a 100%.
Therefore I simply decided to comment out the save in the application will terminate. I know the other option would be to use another context for the edit and then merge the changes or setting my context values until the actual save point. However I do not see any harm in commenting out this line, since I save whatever I want in my application when the user clicks the save button, so my question is: is the save on the application will terminate mandatory? what possible consequences could this have?. It is important to note that the application continues to work just fine after commenting this lines (which is what I expected).
Thank you in advance.
-Oscar
You can save whenever you like.
However, you will never know when the app will terminate. Unlike applications on more conventional platforms e.g desktops, the iPhoneOS will terminate your app (from the apps perspective) at random. The only warning you will get will be the applicationWillTerminate message sent to the app delegate. If you don't handle saves there then it is highly likely that at some point, your users will lose data.
I think you should reconsider your design. It sounds like you're putting calculation into the managedobjects that could (1) be handled elsewhere in code or (2) be handled by transient properties. You shouldn't have a condition in which the managedobject can't be saved at the drop of hat. Doing so makes your datamodel utterly dependent on external code for its internal integrity. This causes problem with maintenance, portability and upgrading.
Its not mandatory to save on application will terminate. You can save when ever you feel appropriate for the context of the app.