UserDefaults Not Saving and Incrementing Properly - swift

I am using UserDefaults to save values to determine when to present an interstitial ad within my application.
Here is the code used to increment the numbers:
if((defaults.integer(forKey: PRESENT_INTERSTITIAL_NUMBER) > defaults.integer(forKey: CURRENT_INTERSTITIAL_NUMBER))){
print("1111")
let oldNumber = defaults.integer(forKey: CURRENT_INTERSTITIAL_NUMBER)
let newNumber = oldNumber + 1
defaults.set(newNumber, forKey: CURRENT_INTERSTITIAL_NUMBER)
print("oldNumber \(oldNumber)")
print("newNumber \(newNumber)")
print("INTER NUMBER \(defaults.integer(forKey: CURRENT_INTERSTITIAL_NUMBER))")
print(defaults.integer(forKey: PRESENT_INTERSTITIAL_NUMBER))
}
I declare user defaults as follows let defaults = UserDefaults.standard
My problem is that is it doesn't always increment the values correctly. I have toyed with this for about an hour to try and work it out.
CASE 1:
CURRENT_INTERSTITIAL_NUMBER = 0
PRESENT_INTERSTITIAL_NUMBER = 4
... run incrementing code ...
CURRENT_INTERSTITIAL_NUMBER = 1
PRESENT_INTERSTITIAL_NUMBER = 4
... run incrementing code ...
CURRENT_INTERSTITIAL_NUMBER = 1
PRESENT_INTERSTITIAL_NUMBER = 4
... run incrementing code ...
CURRENT_INTERSTITIAL_NUMBER = 1
PRESENT_INTERSTITIAL_NUMBER = 4
... run incrementing code ...
CURRENT_INTERSTITIAL_NUMBER = 2
PRESENT_INTERSTITIAL_NUMBER = 4
It appears to be random when the value doesn't properly carry over, but I can't figure out why it is doing this.
Thanks!

Related

Using perform(afterDelay:) within a while loop gives me a logic error?

I am making a timer program which uses a slider to set a timer value and then updates a digital clock display to show the corresponding numerical time remaining as image files.
I am trying to run a 1 second delay function within a while loop, and update the image files each second, essentially trying to create a timer which updates the variables used to determine which images are used in real time.
I am having difficulty assigning counting down correctly: the variables used to set the image files h, min1 and min2 are set to 0 after a 1 second delay. It seems that the while loop calls the delay function once, iterates until the condition is met without delaying the timer and then displays the final values.
I've tried different methods of timing a 1 second delay including using the let timer = Timer. approach and DispatchQueue.main. approach but they don't seem to work.
#IBAction func slider(_ sender: UISlider)
{
self.x = Int(sender.value)
// Note I omitted the rest of this code as it concerned setting images while changing slider value, and used local variables.
}
var x: Int = 60
var h: Int = 1
var min1: Int = 1
var min2: Int = 7
#objc func animate2 ()
{
checkLbl.text = String(h) + ("1")
checkLbl2.text = String(min1) + ("1")
checkLbl3.text = String(min2) + ("1")
self.H2ImageView.image = UIImage(named: "\(h).png")!
self.M1ImageView.image = UIImage(named: "\(min1).png")!
self.M2ImageView.image = UIImage(named: "\(min2).png")!
}
func animate ()
{
var timeLeft = x
var seconds = 60
while timeLeft >= 0
{
(h, _) = x.quotientAndRemainder(dividingBy: 60)
(min1, min2) = x.quotientAndRemainder(dividingBy: 10)
if min1 >= 6
{
min1 = min1 - 6
if h == 2
{
min1 = 0
}
}
checkLbl.text = String(h)
checkLbl2.text = String(min1)
checkLbl3.text = String(min2)
// checkLbl used to track the variables
perform(#selector(animate2), with: nil, afterDelay: 1)
seconds = seconds - 1
if seconds == 0
{
timeLeft = timeLeft - 1
seconds = 60
}
}
}
#IBAction func watchPress(_ sender: UIButton)
{
animate()
}
To summarise: I expected the delay function to update h, min1 and min2 (and therefore update the checkLbl text) every second however these values go straight to 0.
Any help is appreciated, thanks!
You need to understand that performSelector, DispatchQueue.main.asyncAfter and Timer all run code asynchronously after a certain time. This means that line B won't run one second after line A in this example:
checkLbl3.text = String(min2) // A
perform(#selector(animate2), with: nil, afterDelay: 1)
seconds = seconds - 1 // B
Line B will run immediately after line A. And after one second, animate2 will be called.
Therefore, you should not use a while loop. Instead, you should use a Timer like this:
Timer(timeInterval: 1, repeats: true) { (timer) in
if timeLeft == 0 {
timer.invalidate()
}
seconds -= 1
if seconds == 0
{
timeLeft = timeLeft - 1
seconds = 60
}
// update the labels and image views
}
I also recommend you to only store the time left as a number of seconds. Remove your h, min1, min2 and seconds variables. Only calculate them from the time left when you update the UI.

Loop for variables (Xcode 9 - swift 4)

I have I think a stupid question for you, but I start Xcode just one week ago and I have a problem with a loop condition.
for index in 1...4 {
AvatarPlayer1.layer.borderWidth = 4
AvatarPlayer1.layer.cornerRadius = 8
AvatarPlayer1.layer.borderColor = UIColor.white.cgColor
AvatarPlayer1.layer.masksToBounds = false
AvatarPlayer1.clipsToBounds = true //Mask for picture
}
How can I change the 1 value by for number in the loop.
I have try + , + \(index), + index.
You cannot change a variable name in code. Instead, start with an array of your four AvatarPlayer objects and cycle through the array:
let myArrayOfAvatarPlayers = [AvatarPlayer1, AvatarPlayer2, AvatarPlayer3, AvatarPlayer4]
for thisPlayer in myArrayOfAvatarPlayers {
thisPlayer.layer.borderWidth = 4
thisPlayer.layer.cornerRadius = 8
thisPlayer.layer.borderColor = UIColor.white.cgColor
thisPlayer.layer.masksToBounds = false
thisPlayer.clipsToBounds = true //Mask for picture
}
In addition to matt's answer, you could move the setup up stuff to the object init or setup method.
After that, you could use init(repeating:count:) for the list's init. See: https://developer.apple.com/documentation/swift/array/1641692-init

I cant set 2 variables to - each other and equal a third variable in swift

I cant set 2 variables to - each other and equal a third variable in swift
I'm trying to make var1 - var2 == var3 work in swift but I get Result of operator '==' is unused when I use ==
and when I use = I get Cannot assign to value: binary operator returns immutable value this is the code I'm working on.
var pices1 = 1
var pices2 = 1
var warmup: Int = 60
var nexx: Int = 60
func logic() {
if count < 10 {
warmup = 5
count - warmup == nexx
pices1 = 1
pices2 = 1
}
}
== is for checking if two values are equal. = is for assigning a new value to a variable.
Just like when you define a new variable, the destination is on the left and the new value is on the right.
var warmup: Int = 60
In your case, you'll want the following.
nexx = count - warmup

Really fast addition of Strings in swift

The code below shows two ways of building a spreadsheet :
by using:
str = str + "\(number) ; "
or
str.append("\(number)");
Both are really slow because, I think, they discard both strings and make a third one which is the concatenation of the first two.
Now, If I repeat this operation hundreds of thousands of times to grow a spreadsheet... that makes a lot of allocations.
For instance, the code below takes 11 seconds to execute on my MacBook Pro 2016:
let start = Date()
var str = "";
for i in 0 ..< 86400
{
for j in 0 ..< 80
{
// Use either one, no difference
// str = str + "\(Double(j) * 1.23456789086756 + Double(i)) ; "
str.append("\(Double(j) * 1.23456789086756 + Double(i)) ; ");
}
str.append("\n")
}
let duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
print(duration);
How can I solve this issue without having to convert the doubles to string myself ? I have been stuck on this for 3 days... my programming skills are pretty limited, as you can probably see from the code above...
I tried:
var str = NSMutableString(capacity: 86400*80*20);
but the compiler tells me:
Variable 'str' was never mutated; consider changing to 'let' constant
despite the
str.append("\(Double(j) * 1.23456789086756 + Double(i)) ; ");
So apparently, calling append does not mutate the string...
I tried writing it to an array and the limiting factor seems to be the conversion of a double to a string.
The code below takes 13 seconds or so on my air
doing this
arr[i][j] = "1.23456789086756"
drops the execution time to 2 seconds so 11 seconds is taken up in converting Double to String. You might be able to shave off some time by writing your own conversion routine but that seems the limiting factor. I tried using memory streams and that seems even slower.
var start = Date()
var arr = Array(repeating: Array(repeating: "1.23456789086756", count: 80), count: 86400 )
var duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
print(duration); //0.007
start = Date()
var a = 1.23456789086756
for i in 0 ..< 86400
{
for j in 0 ..< 80
{
arr[i][j] = "\(a)" // "1.23456789086756" //String(a)
}
}
duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
print(duration); //13.46 or 2.3 with the string

SystemVerilog array random seed of Shuffle function

I get the same output everytime I run the code below.
module array_shuffle;
integer data[10];
initial begin
foreach (data[x]) begin
data[x] = x;
end
$display("------------------------------\n");
$display("before shuffle, data contains:\n");
foreach (data[x]) begin
$display("data[%0d] = %0d", x, data[x]);
end
data.shuffle();
$display("------------------------------\n");
$display("after shuffle, data contains:\n");
foreach (data[x]) begin
$display("data[%0d] = %0d", x, data[x]);
end
end
endmodule
Output:
------------------------------
before shuffle, data contains:
data[0] = 0
data[1] = 1
data[2] = 2
data[3] = 3
data[4] = 4
data[5] = 5
data[6] = 6
data[7] = 7
data[8] = 8
data[9] = 9
------------------------------
after shuffle, data contains:
data[0] = 8
data[1] = 6
data[2] = 7
data[3] = 9
data[4] = 5
data[5] = 0
data[6] = 1
data[7] = 4
data[8] = 2
data[9] = 3
Is there a way to seed the randomization of the shuffle function?
Shuffle returns the same result every time because you probably run the simulator with the same seed. This is the intended behavior, because when you run a simulation and find a bug, you want to be able to reproduce it, regardless of any design (and to some extent testbench) changes. To see a different output, try setting the seed on the simulator command line. For Incisive this is:
irun -svseed 1 // sets the seed to 1
irun -svseed random // will set a random seed
It's also possible to manipulate the seed of the random number generator using set_randstate, but I wouldn't mess with that.