I'm migrating our codebase to Swift 3 and I've come across a compilation issue that I can't explain or fix.
I have a method in a Double extension that rounds the Double to a certain number of digits:
public func roundToPlaces(places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return round(self * divisor) / divisor
}
For example:
12.34567.roundToPlaces(2) should return 12.35. However, I'm getting a compilation issue for the round method used in this extension. It's saying that I Cannot use mutating member on immutable value: 'self' is immutable.
Any ideas on what's going on here? How do I fix this issue?
I've fixed the issue. Changing round(self * divisor) to (self * divisor).rounded() resolved the compilation issue.
Related
In swift, in Xcode, I am making a calculator app. The app was all working fine but then I realised that the function to solve maths was not working. I had used the function shown in this question. It can solve most problems but when you involve decimal places:e.g. "3/2" you would expect it to return "1.5". It will return 1.0.
Here is the function I am using:
func mathsSolver(item: String) -> String {
let result = NSExpression(format: item).expressionValue(with: nil, context: nil) as! Double
return "\(result)"
}
You can call this function with:
print(mathsSolver(item: "3/2")) //this will print 1.0
Any Ideas?
You have to pass the double value so that you can get result 1.5
print(mathsSolver(item: "3.0/2.0"))
Above you are trying to pass Int value so that it is not giving you the proper result because integer division will always gives you the answer in integer.
Try:
NSExpression(format: "3.0 / 2.0");
this issue has plenty answears on stackoverflow. Check them out. ^_^
How to stop NSExpression from rounding
NSExpression 1/2
Its very popular problem. In swift wench you try to divide one Int number by another Int its automatically cleans up everything what must be after doth. For example if you want to divide 5/2 instead 2.5 you will get = 2. In you example swift has deleted everything after doth and instead 1.5 you got just 1.
To resolve this issue try to use Double or Float instead of Int and everything will be fine!
This question already has an answer here:
Need explanation about random function swift
(1 answer)
Closed 3 years ago.
When generating a random CGFloat, I use the following code. Some explanation here
extension CGFloat{
static func randomFloat(from:CGFloat, to:CGFloat) -> CGFloat {
let randomValue: CGFloat = CGFloat(Float(arc4random()) / 0xFFFFFFFF)
return randomValue * (to - from ) + from
}
}
It used to be OK. Works fine now.
There is a warning, after I upgraded to Swift 5.
'4294967295' is not exactly representable as 'Float'; it becomes '4294967296'
to the line of code
let randomValue: CGFloat = CGFloat(Float(arc4random()) / 0xFFFFFFFF)
How to fix it?
As you know Float has only 24-bits of significand, so 32-bit value 0xFFFFFFFF would be truncated. So, Swift is warning to you that Float cannot represent the value 0xFFFFFFFF precisely.
The short fix would be something like this:
let randomValue: CGFloat = CGFloat(Float(arc4random()) / Float(0xFFFFFFFF))
With using Float.init explicitly, Swift would not generate such warnings.
But the preferred way would be using random(in:) method as suggested in matt's answer:
return CGFloat(Float.random(in: from...to))
or simply:
return CGFloat.random(in: from...to)
Simplest solution: abandon your code and just call https://developer.apple.com/documentation/coregraphics/cgfloat/2994408-random.
I'm just starting out with Swift 3 and I'm converting a Rails project to swift (side project while I learn)
Fairly simple, I have a Rails statement Im converting and Im getting many red errors in Xcode:
let startingPoint: Int = 1
let firstRange: ClosedRange = (2...10)
let secondRange: ClosedRange = (11...20)
func calc(range: Float) -> Float {
switch range {
case startingPoint:
return (range - startingPoint) * 1 // or 0.2
case firstRange:
return // code
default:
return //code
}
}
calc will either have an Int or Float value: 10 or 10.50
Errors are:
Expression pattern of type ClosedRange cannot match values of type Float
Binary operator - cannot be applied to operands of type Float and Int
I understand the errors but I dont know what to search for to correct it. Could you point me in the right direction, please?
Swift is strongly typed. Whenever you use a variable or pass something as a function argument, Swift checks that it is of the correct type. You can't pass a string to a function that expects an integer etc. Swift does this check at compile time (since it's statically typed).
To adhere by that rules, try changing your code to this:
let startingPoint: Float = 1
let firstRange: ClosedRange<Float> = (2...10)
let secondRange: ClosedRange<Float> = (11...20)
func calc(range: Float) -> Float {
switch range {
case startingPoint:
return (range - startingPoint) * 1 // or 0.2
case firstRange:
return 1.0 // 1.0 is just an example, but you have to return Float since that is defined in the method
default:
return 0.0 // 0.0 is just an example, put whatever you need here
}
}
For the first error, you might want to specify ClosedRange to be of type Floats. Something similar to:
let firstRange: ClosedRange<Float> = (2...10)
For the second error, the problem is you are trying to compare a Float (range:Float) with an Int (startingPoint). So I would suggest you convert the startingPoint variable to a Float as well.
I have the following simple extension to Double, which worked fine in everything up to Xcode 8 beta 3
public extension Double {
public func roundTo(_ decimalPlaces: Int) -> Double {
var v = self
var divisor = 1.0
if decimalPlaces > 0 {
for _ in 1 ... decimalPlaces {
v *= 10.0
divisor *= 0.1
}
}
return round(v) * divisor
}
}
As of Beta 4, I am getting "Cannot use mutating member on immutable value: 'self' is immutable" on the round function in the return - has anyone got any clues?
This is due to a naming conflict with the new rounding functions on the FloatingPoint protocol, round() and rounded(), which have been added to Swift 3 as of Xcode 8 beta 4.
You therefore either need to disambiguate by specifying that you're referring to global round() function in the Darwin module:
return Darwin.round(v) * divisor
Or, even better, simply make use of the new rounding functions and call rounded() on v:
return v.rounded() * divisor
I have the following simple extension to Double, which worked fine in everything up to Xcode 8 beta 3
public extension Double {
public func roundTo(_ decimalPlaces: Int) -> Double {
var v = self
var divisor = 1.0
if decimalPlaces > 0 {
for _ in 1 ... decimalPlaces {
v *= 10.0
divisor *= 0.1
}
}
return round(v) * divisor
}
}
As of Beta 4, I am getting "Cannot use mutating member on immutable value: 'self' is immutable" on the round function in the return - has anyone got any clues?
This is due to a naming conflict with the new rounding functions on the FloatingPoint protocol, round() and rounded(), which have been added to Swift 3 as of Xcode 8 beta 4.
You therefore either need to disambiguate by specifying that you're referring to global round() function in the Darwin module:
return Darwin.round(v) * divisor
Or, even better, simply make use of the new rounding functions and call rounded() on v:
return v.rounded() * divisor