User Default Values Changing to Previous Values Seemingly Randomly - Swift - ios

I am creating an app that is a game where there is a need to store the high score. I believe (correct me if I'm wrong on this, but this question made it seem this way) that user defaults are the best way to accomplish this.
Sometimes when I switch between views in my app, the values change to what they previously were. Then I will switch back to another screen, and they will go back to what they should be. This happens kind-of hit and miss, so it is hard to tell, but I think it happens most after it has been set multiple times since the app was last closed; though, I know at least sometimes it only happens after they have been set once.
I have used breakpoints to ensure that the values definitely are not being changed in the code. (I did this by putting a breakpoint where all of the user defaults are set and none of them went off even though the values changed)
The only code dealing with the user defaults is as follows:
UserDefaults.standard.set(newHighScore, forKey"highScore")
-> To set the User Defaults (where newHighScore is an integer)
let highScore = UserDefaults.standarard.value(forKey: "highScore")
-> To retrieve the values
UserDefaults.standard.synchronize()
-> Every time before and after I set or retrieve values (just to play it on the safe side and because it doesn't work so I'm overly cautious)
This question suggested restarting my mac (which I did) and then doing it only in the xcode simulator. I just did that and kept the breakpoints on all the times I set the values.
I have looked at these questions and this question seems similar, but the problem doesn't apply because it was decided that it would be fixed if the code wasn't running in a playground. My code is not running in a playground.
This question also seems similar, but it doesn't apply because the values are returning as null. Mine are just changing to a value they were previously. It is also written in objective-c, so I didn't completely understand what they did to fix it. I looked through the sources it recommended for help, but didn't see anything there that helped me either.
Thanks in advance for any help on what may be my problem. I haven't been able to find anything similar to make it seem like a bug in iOS 10 or Xcode 8 beta, but I am open to any suggestions to make my code work.

Related

Is there a way to run code during an update for an iOS app?

I have recently discovered an error in an app I have previously released for iOS. I am saving something with an incorrect metadata variable which causes a notification to be monthly instead of daily.
This is trivial to fix, it just involves looping through all the currently saved objects and changing a 1 to a 0. However it would be preferable to me to be able to do this during the update that fixes the error. Is there a way then of running code as part of an update?
Otherwise I imagine the next best way of solving the problem would be to run the loop the next time the app is opened.
I have looked around online and have only found solutions which involve running one off code on app start up. I am therefore wondering if I am missing something because this seems to be the sort of thing that a lot of apps will need to have happen to them if they need to reconfigure how their data is saved or equivalent.
If you are not using core data and overriding the light weight migration to make an changes needed there, then the only way is to use User Defaults and check for a var you know does not exist, run the code, then add the var so as to not run it again.
func updateDB() {
if !UserDefaults.standard.bool(forKey: MyProject.DBFixKey) {
// Fix DB
UserDefaults.standard.set(true, forKey: MyProject.DBFixKey)
}
}

NSAsychronousFetchResult after the app is DidEnterBackground

I have a client app with coredata as its back end. Its simple enough, with two entities.
UPDATE: Using CloudKit as the sync service. I'm not really sure what is going on there. Except I can query and get results, incase things don't automatically work. The problem is, as I noticed with most third-party sync-service providers. 95% of the time, they all work. Its when I test it with a more than a few devices / simultaneous calls that some undesired change comes in.
This question is more about iOS and coredata than the actual syncing architecture.
there are times when there is definite sync data loss. I really can't tell when and how. That im still figuring out. Sometimes initial sync takes a long time (if theres existing data) and the user might close the app, (some people double press the home button and actually close apps!).
But no matter what I do, sometimes i miss an object, sometimes an attribute.
So I saw this NSAsynchronousFetchRequest and I thought about giving me an option to check if all local-data (coredata) is okay, to see if theres anything missing.
Perhaps i could use a simple predicate to see of some managedObject.title == nil and fetch its identifier. Collect those faulty objects and request the truth server for data for these objects? Is this a good use of NSAsynchronousFetchRequest?
If yes, when during the lifetime of the app would this be good?
Im thinking maybe after applicationDidEnterBackround would be a good time..? Then If I do get it, will need a good way to manage CoreData in the background!
If no, well.. Really don't know wat to do then.
Im trying to actually do this, will update with my results.
UPDATE: Question updated to reflect the use of Cloudkit

Variable Corrupted / Bloated

I have an app and some users experience an error where it seems a variable gets corrupted, causing the app to crash. I am not sure what causes this corruption and have never been able to replicate the error on my test devices.
However today I got hold of a problem user's device and was able to perform po brokenvar in the console and got an output of the corrupted variable.
Here's the top 6 'lines' from the debugger:
The N‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√´‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂‚àö¬¥‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö‚Ć‚àö√°‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂¬¨¬•‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚àö¬∞‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√´‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö√ë‚Äö√тĆ‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö‚Ć‚àö√°‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àǬ¨¬®¬¨‚Ä¢‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√´‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö√ë‚Äö√тĆ‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö‚Ć‚àö√°‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√´‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö√ë‚Äö√тĆ‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂¬¨‚àû‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√´‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂‚àö¬¥‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö‚Ć‚àö√°‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√
And the bottom 6 'lines':
´¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ‚Äö√†√∂‚àö√∫‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚àö√´‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö√ë‚Äö√тĆ‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö‚Ć‚àö√°‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√Ñ√∂‚àö‚Ƭ¨¬•¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ‚Äö√†√∂‚àö√∫¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√Ü‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂‚àö‚à´¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ‚Äö√†√∂‚àö√∫¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú‚Äö√Ñ√∂‚àö√ë‚àö‚àÇ‚Äö√†√∂‚Äö√тĆ‚Äö√†√∂‚Äö√†√á‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂‚Äö√†¬¥¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ‚Äö√†√∂‚àö√∫¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√Ü‚Äö√Ñ√∂‚àö‚Ć‚àö‚àÇ‚Äö√†√∂‚àö‚à´¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ‚Äö√†√∂‚àö√∫¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®‚àö√ú¬¨¬®¬¨¬Æ¬¨¬®¬¨√ܬ¨¬®¬¨¬Æ¬¨¬®¬¨¬¢bel oven is marked but in good condition.
There is a lot of more gibberish in the middle - I copied and pasted the whole lot into TextEdit and it turned out being a ~170mb text file.
You can see the start The N and the end bel oven is.. which looks like the actual comment the user entered.
I did the po brokenvar output twice and compared the top/bottom 6 lines, they were exactly the same each time. This makes me think that it is a saving issue that has occurred once, and not something that is getting corrupted on the fly - though I may be way off..
The user would have entered plain text into a UITextField, which gets saved into a SQLite database. The crash occurs after reading the variable from the database, when I attempt to set the UITextField's text as the NSString.
The app is using a SQLite wrapper I found ages ago, lost the original link but found it here: https://github.com/ConnorD/simple-sqlite/blob/master/Sqlite.h
There doesn't seem to be any common thread with the handful of users who have experienced the problem. It might be the first time they use the app, or the hundredth.
I'm not sure why it is coming out corrupt/gibberish/garbled like this, or where to move on from here.
Any suggestions on how to proceed would be greatly appreciated.

NSFetchRequest - Includes Pending Changes

I'm having issues with my NSFetchedResultsController, which seem to be fixed by turning IncludesPendingChanges on, and this worries me. (I've found this to not be true, including pending changes does not help.)
What happens is that my Fetched Results Controller correctly fetches and displays my objects on a full API refresh. Stepping through, I have confirmed that this full API refresh's temporary context is saved and merged without error.
However, if I then return to a view which does this same fetch request from a different navigation flow, only one partially complete object is returned and displayed, rather than the complete set of objects. If I then do a full API Refresh at this point, the refresh displays the correct objects.
I believe my issue may be that mergeChangesFromContextDidSaveNotification is not propagating to the main context, but from my logs and stepping through, it seems to me that it is saving correctly. I'm not sure where to go from here. While IncludesPendingChanges fixes the symptom, I don't believe it fixes the underlying issue.
As some added information, I'm using this framework for my Core Data Management: https://github.com/vokalinteractive/CoreDataManager-iOS
I am turning on includesPendingChanges by adding on line 156 of VIFetchedResultsController.m
[fetchRequest setIncludesPendingChanges:YES]
Edit Whatever fluke caused me to believe includesPendingChanges to YES fixed the problem is no longer present. Turns out this project had some seriously hairy memory management, and after spending all day cleaning that up, I'm still not closer to making this work. Still at the same point though, it looks like the changes are not propagating to the main datastore, or aren't sticking.
As a hint, like I mentioned in my comment below, even when I specify "includePendingChanges:YES", Logging out my fetched objects with:
[self.fetchedResultsController.fetchedObjects description]
ends with "includesPendingChanges: NO". Any idea what can cause this?
Perhaps you got it the wrong way round. The default of includesPendingChanges is YES, as this is the behavior you usually want. That your UI updates getting corrupted is sort of expected.
Setting this attribute to NO is really just meant to facilitate fetches with NSDictionaryResultType, especially when including simple aggregations that can be dealt with on the database level.
I suspect this is by no means an error by you, but a possible flaw of the framework you are using. Anyway, what you identify as an issue, is really just expected behavior.
See the two short paragraphs in the documentation where this is explained quite well.

Delphi, TPopupMenuItems behaving strangely after the application is idle for a long time

I have a problem I cannot solve. Of course here I just expect to have a suggestion that can help me to find a solution.
Basically my application is full of runtime generated TPopupMenuItems (while all the TPopupMenus are hardcoded). In some cases what I do is simply hide/show or enable/disable items, in other cases I create items at runtime.
In some machines only, after leaving the application running for days (2 or more) the popupmenus don't work anymore correctly.
The behaviour is:
all the TPopupmenu items look are the same, and execute the same action.
The action is the one performed by the first TPopupMenuItem of the application (the first generated at runtime when the application starts, this is the only hint I have).
Imagine in correct scenario I have (in a 3-items-TPopupMenu):
Item23
Item24
Item25
after the problem I see:
Item1
Item1
Item1
(where Item1 is the TPopupMenuItem belonging to another TPopupMenu).
Does this tell you something?
Thanks.
Update:
I tried to look at the code of my popupmenus and I found what could be a common cause, and this explains also why FastMM4 didn't find this:
while mnuItem.Count > 0 do
mnuItem.Delete(0);
Delete (I just read in the documentation) doesn't free the item, I should call free instead. Anyway when closing the application the main popupmenus are freed correctly, and FastMM4 doesn't complain. So this is probably the solution, now I don't know why Delete was used, I didn't write that code.
Further update:
I tried to make a sample application, I couldn't reproduce the problem, but for sure I noticed that using this is much more performant (I tried a loop with 10000 recursions):
while mnuItem.Count > 0 do
mnuItem.Items[0].Free;
I will try for this in my app (but I need to let some days pass to really know if I got the problem, ayway for sure this is a major improvement anyway).
I confirm that the problem was linked to Delete instead of Free. Popupmenu wsa refreshed every minute on the machines that had the problem (so it was not OS or HW specific, just config specific). Then according to user settings the menu could have 10 to 100 items, so leaving it idle for days made it possible to hit the handle limit.
By the way it also makes no sense to refresh the popupmenu in that way, so I found also an optimizaion removed a bug.
Did you check for memory leakage and handles that aren't freed?

Resources