UISlider ValueChanged action not working - ios

I want to calculate a number in real-time with UISlider, this is my method:
#IBAction func HPsliderValueChanged(_ sender: CustomUISlider) {
calculator.HPPercentage = Double(HPSlider.value)
HPValue.text = String(Int(HPSlider.value * 100)) + " %"
resultLabel.text = String(calculator.calculate())
}
Both the HPValue label and resultLabel are expected to change value when user swipes on slider, however, now only HPValue label changes, the resultLabel doesn't work.
calculator is not nil, here's its code:
class TurretDiveCalculator {
var hero: Heroes = .taka
var build = [DefenseItems](repeatElement(DefenseItems(name: "Empty Item", index: 0, price: 0, image: #imageLiteral(resourceName: "EmptyItem")), count: 6))
var HPPercentage: Double = 0
func calculate() -> Int {
let baseHP = hero.HPLow + (hero.HPHigh - hero.HPLow) / 12 * Double(hero.level)
let baseDefense = hero.armorLow + (hero.armorHigh - hero.armorLow) / 12 * Double(hero.level) + hero.shieldLow + (hero.shieldHigh - hero.shieldLow) / 12 * Double(hero.level)
var buildHP = 0.0
var buildDefense = 0.0
for item in build {
buildDefense += item.armor
buildDefense += item.shield
buildHP += item.HP
}
let fullHP = baseHP + buildHP
var HP = fullHP
let defense = baseDefense + buildDefense
var numberOfShots = 0
while HP > 0 {
let perShotDamageRaw: Double = 330 + Double(numberOfShots) * 0.09 * fullHP
let mitigatedDamage: Double = 0.09 * perShotDamageRaw + 0.9 * perShotDamageRaw / (100 + defense) * 100
HP -= mitigatedDamage
numberOfShots += 1
}
return numberOfShots
}
}
How do I get resultLabel's value to change in real-time, too?

As can be seen in the chat, we managed to find the problem.
This answer is just some general debugging tips and tricks when a problem like this arises.
The original problem was:
now only HPValue label changes, the resultLabel doesn't work.
Lets find out where the problem is. Here's the code:
resultLabel.text = String(calculator.calculate())
Two things can go wrong here:
The resultLabel is not properly wired. To see if that is the case, try setting the value to a plain ol' string and see if you can see that. I you can, well, the textfield is wired properly.
The calculate() method returns an unexpected value. Try verifying what the method returns by adding a print statement just before the return
And as you can see in the chat, once we'd isolated where the problem occurred it was easier for #bright-future to track down the issue.
Hope this helps anybody when they are trying to debug a problem :)

Related

Show what image I am on in a UIScrollview swift

Say I have 4 images that i download
I want to reverse the number of the image that I am on. Right now the image starts at 4/4 but I want it to read 1/4. So basically I am tying to reverse the numbers. This function is finding which number of the image that I am on. So the closer it get to the last image it turns the number to 1. I want the opposite effect. I want the number of the last image to turn to 4. So if i swipe right the number goes down from 4/4 to 3/4 to 2/4 to 1/4. But I want the first image to be 1 not 4 so it goes 1/4 to 2/4 to 3/4 to 4/4.
Here is how I am doing it:
//MARK: Set up and download Promotions
var numberPromotions = 0;
var imageSize = 0;
private var promos = Array<(picture: String, path: String)>()
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
print("Scroll finished")
print("My promot gus" , self.numberPromotions)
print("Scroll number", scrollView.contentOffset.x)
print("IMAGE size " , self.imageSize)
var myPlace : Double = 0
var totalSize : Double = 0
let scrollviewOffset = Double(scrollView.contentOffset.x)
print("int Scroview " , scrollviewOffset)
totalSize = Double(self.imageSize * (numberPromotions - 1))
print("To;tal size" , totalSize)
if scrollviewOffset == 0 {
myPlace = Double(numberPromotions)
}else
{
myPlace = Double(totalSize / scrollviewOffset)
print("Gus Place" , myPlace)
}
print(myPlace % 1 == 0.5)
if myPlace % 1 == 0.5
{
print("Not a whole number Adding 0.5")
myPlace = myPlace + 0.5
}
print("My place", myPlace)
var myString : String
let myPlaceString = String(Int(myPlace))
myString = myPlaceString + "/" + String(numberPromotions)
numOfPromoLabel.text = myString
}
Try this:
myString = (String(numberPromotions)-myPlaceString + 1) + "/" + String(numberPromotions)

Swift Array Performance Issue?

I'm not sure if there is an issue or not, so i'm just gonna write it down.
I'm developing using swift, xcode 7.2 , on iphone 5s.
And calculating execution time using
NSDate.timeIntervalSinceReferenceDate()
I created 2 arrays, one with 200,000 elements and one with 20.
and try to have random access to their elements. accessing elements on big one is almost 55 times slower! i know its bigger but isn't this O(1) ?
I also tried the same on java and the accessing speed is the same for big and small array.
From CFArrayheader in apple documentation, i found this:
Accessing any value at a particular index in an array is at worst O(log n), but should usually be O(1).
but it think this cant be true based on the numbers i've tested.
I know i didn't make a big test or anything special, but the fact that its not working is really messing with my head!
i kinda need this for what i'm working on. and the algorithm is not working on swift and iOS and its working on java and android.
let bigSize:Int = 200000
var bigArray = [Int](count:bigSize,repeatedValue:0)
let smallSize:Int = 20
var smallArray = [Int](count:smallSize,repeatedValue:0)
for i in 0..<bigSize
{
bigArray[i] = i + 8 * i
}
for i in 0..<smallSize
{
smallArray[i] = i + 9 * i
}
let indexBig = Int(arc4random_uniform(UInt32(bigSize)) % UInt32(bigSize))
let indexSmall = Int(arc4random_uniform(UInt32(smallSize)) % UInt32(smallSize))
var a = NSDate.timeIntervalSinceReferenceDate()
print(bigArray[indexBig])
var b = NSDate.timeIntervalSinceReferenceDate()
print(b-a) \\prints 0.000888049602508545
a = NSDate.timeIntervalSinceReferenceDate()
print(smallArray[indexSmall])
b = NSDate.timeIntervalSinceReferenceDate()
print(b-a) \\prints 6.90221786499023e-05
java :
(accessing one element is so fast on java and its on pc, so i access more elements, but same number on both arrays)
int bigSize = 200000;
int[] bigArray = new int[bigSize];
Random rand = new Random();
int smallSize = 20;
int[] smallArray = new int[smallSize];
for(int i = 0;i < bigSize;i++)
bigArray[i] = i + i * 8;
for(int i = 0;i < smallSize;i++)
smallArray[i] = i + i * 8;
int smallIndex = rand.nextInt(smallSize);
int bigIndex = rand.nextInt(bigSize);
int sum = 0;
long a = System.currentTimeMillis();
for(int i = 0;i < 10000;i++)
{
sum += bigArray[rand.nextInt(bigSize)];
}
System.out.println(sum);
long b = System.currentTimeMillis();
System.out.println(b-a); //prints 2
a = System.currentTimeMillis();
sum = 0;
for(int i = 0; i < 10000;i++)
{
sum += smallArray[rand.nextInt(smallSize)];
}
System.out.println(sum);
b = System.currentTimeMillis();
System.out.println(b - a); //prints 1
If you change the order of your two tests, you'll find that the performance is flipped. In short, the first test runs more slowly than the second one, regardless of whether it's the small array or the big one. This is a result of some dynamics of print. If you do a print before you perform the tests, the delay resulting from the first print is eliminated.
A better way to test this would be to create a unit test, which (a) repeats the subscript operator many times; and (b) uses measureBlock to repeat the test a few times to check for standard deviation and the like.
When I do that, I find the access time is indistinguishable, consistent with O(1). This were my unit tests:
let bigSize: Int = 200_000
let smallSize: Int = 20
func testBigArrayPerformance() {
let size = bigSize
let array = Array(0 ..< size).map { $0 + 8 * $0 }
var value = 0
measureBlock {
let baseIndex = Int(arc4random_uniform(UInt32(size)))
for index in 0 ..< 1_000_000 {
value += array[(baseIndex + index) % size]
}
}
print(value)
print(array.count)
}
func testSmallArrayPerformance() {
let size = smallSize
let array = Array(0 ..< size).map { $0 + 8 * $0 }
var value = 0
measureBlock {
let baseIndex = Int(arc4random_uniform(UInt32(size)))
for index in 0 ..< 1_000_000 {
value += array[(baseIndex + index) % size]
}
}
print(value)
print(array.count)
}
Admittedly, I've added some mathematical operations that change the index (my intent was to make sure the compiler didn't do some radical optimization that removed my attempt to repeat the subscript operation), and the overhead of that mathematical operation will dilute the subscript operator performance difference. But, even when I simplified the index operator, the performance between the two renditions was indistinguishable.

swift - Increase speed of objects over time

I'm looking for a way to increase the pace of my game the longer you play it, I would like to achieve this by increasing the frequency of obstacles generated either after a certain time i.e. every 30 seconds or preferably after 10 objects (trees), have been generated so the longer you play the harder it gets.
This is my current set up, I use repeatActionForever how could I change this to something like repeatAction10Times with a different delay variable for each loop?
//in didMoveToView
treeTexture1 = SKTexture(imageNamed: "tree")
treeTexture1.filteringMode = SKTextureFilteringMode.Nearest
var distanceToMove = CGFloat(self.frame.size.width + 0.1);
var moveTrees = SKAction.moveByX(-distanceToMove, y:0, duration:NSTimeInterval(0.006 * distanceToMove));
var removeTrees = SKAction.removeFromParent();
moveAndRemoveTrees = SKAction.sequence([moveTrees, removeTrees]);
var spawn = SKAction.runBlock({() in self.spawnTrees()})
//this delay is what I would like to alter for each loop
var delay = SKAction.waitForDuration(NSTimeInterval(1.2))
var spawnThenDelay = SKAction.sequence([spawn, delay])
var spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
func spawnTrees() {
var tree = SKNode()
tree.position = CGPointMake( self.frame.size.width + treeTexture1.size().width * 2, 0 );
tree.zPosition = -10;
var height = UInt32( self.frame.size.height / 1 )
var height_max = UInt32( 220 )
var height_min = UInt32( 100 )
var y = arc4random_uniform(height_max - height_min + 1) + height_min;
var tree1 = SKSpriteNode(texture: treeTexture1)
tree1.position = CGPointMake(0.0, CGFloat(y))
tree1.physicsBody = SKPhysicsBody(rectangleOfSize: tree1.size)
tree1.physicsBody?.dynamic = false
tree1.physicsBody?.categoryBitMask = treeCategory;
tree1.physicsBody?.collisionBitMask = 0
tree1.physicsBody?.contactTestBitMask = 0
tree.addChild(tree1)
tree.runAction(moveAndRemoveTrees)
trees.addChild(tree)
}
You should try to use the simple action.speed code.
For example: Instead of running the action spawnThenDelay ten times and then running some code and repeating, try making a counter. Create a global variable at the very top of the code called counter, or whatever you want to call it. In spawnTrees(), change the code to this:
func spawnTrees() {
var tree = SKNode()
tree.position = CGPointMake( self.frame.size.width + treeTexture1.size().width * 2, 0 );
tree.zPosition = -10;
counter++
... }
And then in the update(), check to see if counter is above 10.
if counter == 10 {
self.actionForKey("spawnThenDelayForever").speed += 10.0 // Or some integer/float like that
counter = 0
}
Now, what this will do is run the code inside that if-statement for every 10 times you spawn something. But to do this, you'll have to update your calling of spawnAndThenDelayForever to add a key to reference it with.
self.runAction(spawnThenDelayForever, withKey "spawnThenDelayForever")
Let me know if there are any syntactical errors in what I gave you, or if it doesn't work quite right.

Most effecient way to calculate this in swift (simple math)

The question is related to calculating an increase in currency.
Loop over this n times, and let's say you start with $50k and your multiplier is 2. Something like b * 2 + a
This is the correct result:
$50,000.00
$100,000.00
$250,000.00
$600,000.00
$1,450,000.00
$3,500,000.00
$8,450,000.00
$20,400,000.00
$49,250,000.00
So just to be clear, the question is about efficiency in swift, not simply how to calculate this. Are there any handy data structures that would make this faster? Basically I was just looping through how many years (n) adding 2 (200%) and incrementing a couple temp variables to keep track of the current and previous values. It feels like there has got to be a much better way of handling this.
$50k base
$50k * 2 + 0 (previous value) = $100k
$100k * 2 + $50k = $250k
$250k * 2 + $100k = $600k
etc.
Code:
let baseAmount = 50000.0
let percentReturn = 200.0
let years = 10
// Calc decimal of percent.
var out: Double = 0.0
var previous: Double = 0.0
let returnPercent = percentReturn * 0.01
// Create tmp array to store values.
var tmpArray = [Double]()
// Loop through years.
for var index = 0; index < years; ++index
{
if index == 0
{
out = baseAmount
tmpArray.append(baseAmount)
}
else if index == 1
{
out = (out * returnPercent)
tmpArray.append(out)
previous = baseAmount
}
else
{
let tmp = (tmpArray.last! * returnPercent) + previous
previous = tmpArray.last!
tmpArray.append(tmp)
}
}
println(tmpArray)
Here are some ideas for improving efficiency:
Initialize your array to the appropriate size (it isn't dynamic; it is always the number of years)
Remove special cases (year 0 and 1 calculations) from the for-loop
Code:
func calculate(baseAmount: Double, percentReturn: Double, years: Int) -> [Double] {
// I prefer to return an empty array instead of nil
// so that you don't have to check for nil later
if years < 1 {
return [Double]()
}
let percentReturnAsDecimal = percentReturn * 0.01
// You know the size of the array, no need to append
var result = [Double](count: years, repeatedValue: 0.0)
result[0] = baseAmount
// No need to do this in the loop
if years > 1 {
result[1] = baseAmount * percentReturnAsDecimal
}
// Loop through years 2+
for year in 2 ..< years {
let lastYear = result[year - 1]
let yearBeforeLast = result[year - 2]
result[year] = (lastYear * percentReturnAsDecimal) + yearBeforeLast
}
return result
}
Efficiency in terms of speed I found this to be the fastest implementation of your algorithm:
let baseAmount = 50000.0
let returnPercent = 2.0
let years = 10
// you know the size of the array so you don't have to append to it and just use the subscript which is much faster
var array = [Double](count: years, repeatedValue: 0)
var previousValue = 0.0
var currentValue = baseAmount
for i in 0..<years {
array[i] = currentValue
let p2 = currentValue
currentValue = currentValue * returnPercent + previousValue
previousValue = p2
}
print(array)

Create Loop for Amortization Schedule in Swift

I'm looking to figure out a simple loop in order to calculate an amortization schedule in Swift.
So far, here is my setup on Playground:
let loanAmount: Double = 250000.00
let intRate: Double = 4.0
let years: Double = 30.0
var r: Double = intRate / 1200
var n: Double = years * 12
var rPower: Double = pow(1 + r, n)
var monthlyPayment: Double = loanAmount * r * rPower / (rPower - 1)
var annualPayment: Double = monthlyPayment * 12
For the actual loop, I'm unsure how to fix the code below.
for i in 0...360 {
var interestPayment: Double = loanAmount * r
var principalPayment: Double = monthlyPayment - interestPayment
var balance: Double; -= principalPayment
}
Looking to generate a monthly schedule. Thanks in advance for any tip.
I'm guessing you mean to declare the balance variable outside the loop, and to decrement it inside the loop:
// stylistically, in Swift it's usual to leave
// off the types like Double unless you have a
// reason to be explicit
let loanAmount = 250_000.00
let intRate = 4.0
let years = 30.0
// since these are one-off calculations, you
// should use let for them, too. let doesn't
// just have to be for constant numbers, it just
// means the number can't change once calculated.
let r = intRate / 1200
let n = years * 12
let rPower = pow(1 + r, n)
// like above, these aren't changing. always prefer let
// over var unless you really need to vary the value
let monthlyPayment = loanAmount * r * rPower / (rPower - 1)
let annualPayment = monthlyPayment * 12
// this is the only variable you intend to "vary"
// so does need to be a var
var balance = loanAmount
// start counting from 1 not 0 if you want to use an open
// (i.e. including 360) range, or you'll perform 361 calculations:
for i in 1...360 {
// you probably want to calculate interest
// from balance rather than initial principal
let interestPayment = balance * r
let principalPayment = monthlyPayment - interestPayment
balance -= principalPayment
println(balance)
}
This should print out the correct balances going down to zero for the final balance (well actually 9.73727765085641e-09 – but that's a whole other question).
If you wanted to create a monthly balance, say in an array, you could add an additional array variable to store that in:
var balance = loanAmount
//array of monthly balances, with the initial loan amount to start with:
var monthlyBalances = [balance]
for i in 1...360 {
let interestPayment = balance * r
let principalPayment = monthlyPayment - interestPayment
balance -= principalPayment
monthlyBalances.append(balance)
}
Advanced version for anyone who's interested
You might wonder if there's a way to declare monthlyBalances with let rather than var. And there is! You could use reduce:
let monthlyBalances = reduce(1...360, [loanAmount]) {
payments, _ in
let balance = payments.last!
let interestPayment = balance * r
let principalPayment = monthlyPayment - interestPayment
return payments + [balance - principalPayment]
}
However this is a bit nasty for a couple of reasons. It would much much nicer if the Swift standard library had a slightly different version of reduce called accumulate that generated an array out of a running total, like this:
let monthlyBalances = accumulate(1...360, loanAmount) {
balance, _ in
let interestPayment = balance * r
let principalPayment = monthlyPayment - interestPayment
return balance - principalPayment
}
And here's a definition of accumulate:
func accumulate<S: SequenceType, U>
(source: S, var initial: U, combine: (U, S.Generator.Element) -> U)
-> [U] {
var result: [U] = []
result.append(initial)
for x in source {
initial = combine(initial, x)
result.append(initial)
}
return result
}

Resources