userDefaults reset / wiped after iOS 10.3 update - sprite-kit

In my SpriteKit game I use UserDefaults to save high scores etc. Works fine, everything working smoothly.
however - I just updated some devices to iOS 10.3 (release, not beta) and I noticed that previously saved data is wiped...
new data is preserved - eg - a new high score is recorded, so the userDefaults are still being set once they are created.. but I wouldn't have expected 10.3 to wipe the old data ??
I imagine this is something to do with the new APFS ?
I have not tested this in any other apps yet - has anyone else seen this issue ? any idea how to prevent this happening in future ?
thanks.
example of setting a default: (Swift 3)
if (UserDefaults.standard.value(forKey: "highScoreLife") == nil) {
highScoreLife = 0
UserDefaults.standard.set(highScoreLife, forKey: "highScoreLife") } else {
highScoreLife = Int32(UserDefaults.standard.integer(forKey: "highScoreLife") as Int)
}

Related

GKLeaderboard's localPlayerScore delay after saving a GKScore

I'm trying to get a user's new leaderboard rank after scoring a high score and I found it takes about 5 seconds for the GKLeaderboard scores to update. I've tested the code against a Release build (from Xcode) and the delay is still there.
let score = GKScore(leaderboardIdentifier: leaderboardId)
score.value = Int64(highScore)
GKScore.report([score]) { _ in
// Adding a 5 second delay here solves the problem.
let leaderboard = GKLeaderboard()
leaderboard.identifier = leaderboardId
leaderboard.loadScores { _, _ in
// leaderboard.localPlayerScore shows data from before saving the new score.
}
}
Is there a way around this? The 5-second delay seems flaky. Maybe once the app is in the App Store this delay is no longer there?
I could probably create a workaround by storing the scores before the user plays the game and locally calculate the new rank but the shared code should avoid the need for that, right?

App does not receive DeviceMotion updates in background (WatchOS 6)

I'm developing an application for Apple Watch that acquires accelerometer, gyroscope data through DeviceMotion, and heart rate through HKWorkout.
Until the application stays in the foreground, all works well. However, when it enters the inactive state (when the user lowers the wrist), for some time it works, but at a certain point it stops. Furthermore, when the app goes in background, the app stops to collect new DeviceMotion updates, but I think that the observer of the heart rate continues to work since the green led still remains on.
The code I use for DeviceMotion is:
if self.motion.isDeviceMotionAvailable {
self.motion.deviceMotionUpdateInterval = 1.0 / 100.0
self.motion.showsDeviceMovementDisplay = true
self.motion.startDeviceMotionUpdates(using: .xMagneticNorthZVertical, to: OperationQueue.main, withHandler: { (data, error) in
if let d = data {
//collecting data
}
}
}
The code I use for heart rate:
let workoutConfiguration = HKWorkoutConfiguration()
workoutConfiguration.activityType = .crossTraining
workoutConfiguration.locationType = .indoor
do {
if workoutSession == nil {
workoutSession = try HKWorkoutSession(healthStore: HealthDataManager.sharedInstance.healthStore!, configuration: workoutConfiguration)
workoutSession?.startActivity(with: Date())
}
} catch {
print("Error starting workout session: \(error.localizedDescription)")
}
HealthDataManager.sharedInstance.observeHeartRateSamples { (heartRate) -> (Void) in
print("heart rate sample: \(heartRate)")
self.lastHearRateSample = heartRate
}
Since Apple Documentation states (https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings)
While a workout session is active, your app can continue to run in the background. This lets your app monitor the user and gather data throughout the activity. Additionally, it ensures that your app appears whenever the user checks their watch.
I have thought that there was no need to manage the behavior of the app in these cases. However, it seems that something must be done. What's the best way to collect new DeviceMotion data also in the background state (and in the inactive one)?
It turned out that the application went in the background because of the health kit workout. However, I was using too many resources and the system suspended the app.

SCNCamera.exposureOffset not working in iOS13

SCNCamera.wantsHDR is true. Yet any changes to SCNCamera.exposureOffset are not visible on iOS13 devices. But it is working perfectly fine on iOS12.
if let camera = self.sceneView.pointOfView?.camera {
camera.exposureOffset = -5
}
You said absolutely right, if someone wanna use exposureOffset instance property in SceneKit, he/she needs to activate a wantsHDR property at first:
var wantsHDR: Bool { get set }
In real code it might look like this:
sceneView.pointOfView!.camera!.wantsHDR = true
sceneView.pointOfView!.camera!.exposureOffset = -5
But there's a bug in iOS 13 and iOS 13 Simulator. However, if you disable allowsCameraControl, exposureOffset works fine.
sceneView.allowsCameraControl = false
Here's how exposureOffset changes from -2 to 2:

SKAction scaleTo not working on iPhone 5S

I've found a strange behavior while using the iPhone 5S as development-target(Simulator and real device).
I'd like to scale a SKSpriteNode with an SKAction.scaleTo. This works fine on the iPhone 4S and the iPhone 5 simulator(Tested with iOS 7.0.3 and iOS 8).
But on the iPhone 5S simulator, the node doesn't scale. Also on my real iPhone 5S it doesn't scale.
Here is my code:
for tile in tileArray{
if(tile.color == searchColor){
var action = SKAction.scaleTo(0.5, duration: 0.5)
var action2 = SKAction.scaleTo(1, duration: 0.5)
tile.runAction(SKAction.repeatActionForever(SKAction.sequence([action, action2])))
}
}
EDIT:I've now found out, that the if-block doesn't get called on the iPhone 5S. I don't know why. For the other iPhones it works.
But as you see, the two colors are the same:
UIDeviceRGBColorSpace 0.203922 0.286275 0.368627 1
UIDeviceRGBColorSpace 0.203922 0.286275 0.368627 1
How is that possible?
Important: Other SKaction.scaleTo actions are working without any problems.
You are not comparing colors, you are comparing pointer values:
if(tile.color == searchColor)
This tests whether tile.color and searchColor both point to the same memory address. Depending on how the color is created, these addresses may be different. Try testing the individual color components as in:
if (tile.color.r == seachColor.r && tile.color.g == searchColor.b && etc ..)
Note that equality for floating point values is "relative".
The cause is the UIDeviceRGBColorSpace, which is different on the iPhone 5S. So I had to create an object-class which has also a name in it. Now I have to add the colornames to the class too, but I can compare the colors that way:
var color1 = ColorClass("myRed", color:theColor)
var color2 = ColorClass("myRed", color:theColor2)
if(color1.name == color2.name){
}
Of course this fix is really case-dependant. So for many others, this solution won't be good enough for their purposes.

Code doesn't work on iPhone but works on simulator

I have this code in my live chat.
if (TRUE && (balloonsOn != NO || !htmlStart)) {
balloonsOn = TRUE;
htmlStart = [self createChatLines: balloonsOn ? #"htmlformat-balloons" : #"htmlformat"];
if (chatLines > 0){
chatLines = 0;
[self updateView];
}
}
On the simulator it works fine but on the phone it doesn't work. It has worked before many times but now it stopped working on the phone. Why is this happening?
As far as I can see, there should be nothing that wouldn't work on the iPhone.. The only thing I can suppose, is you are using that strings without caring of the case-sensitiveness of iOs. The simulator is case insensitive but iOs is.. Let me know :)
What is the variable 'TRUE' ? I think having that as a variable name is probably the issue, rename it something else and see if it works.