I want to get a value of Int32 through an Int32 Pointer.
var result:Int32 = 32
var y = withUnsafePointer(&result, {(point:UnsafePointer<Int32>) -> UnsafePointer<Int32> in
return point
})
It is like every UnsafePointer<>. Example: NSErrorPointer which is an AutoreleasingUnsafePointer<NSError?> you can get the value with the memory attribute.
Use the attribute memory
var errPtr: UnsafePointer<NSError> = ...
var err: NSError = errPtr.memory // not optional
Solution to your example is very easy then:
var result:Int32 = 32
var y = withUnsafePointer(&result, {(point:UnsafePointer<Int32>) -> UnsafePointer<Int32> in
return point
})
y.memory // in the playground it shows 32 :-D
There is no dereference operator in Swift, in C it was the aterisk *, but that is not possible in Swift.
The documentation is very helpful.
The type UnsafePointer<Memory> has a subscript operator. Provided that the pointer points to something, subscript 0 always exists, so this works in a playground and it has the advantage that the reference guide has the subscript documented but not the memory property.
var result:Int32 = 32
var y = withUnsafePointer(&result, {(point:UnsafePointer<Int32>) -> UnsafePointer<Int32> in
return point
})
y[0] // 32
Related
I was wondering, what is a good way to fix the following compiler error?
class A {
var x: Int32
init() {
x = -1
}
}
let a: A? = nil
// No issue.
let ok: Int = Int(a?.x ?? -1)
// Type of expression is ambiguous without more context
let CONSTANT: Int = -1
let not_ok: Int = Int(a?.x ?? CONSTANT)
Any idea why we are getting Type of expression is ambiguous without more context if we use CONSTANT instead of -1?
What is a good way to fix the compiler error (retain same class, same type and same CONSTANT), yet still retain 1 liner?
It's for the same reason that you can say this:
let d = 3.0
let d2 = d + 1
But not this:
let i = 1
let d3 = d + i
Swift will cast the literal 1 to the required numeric type (here, Double), but it won't cast a variable away from its type.
So the answer is: make the types match.
The ?? operator is declared like this:
func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T)
rethrows -> T
In the expression Int(a?.x ?? -1), the compiler needs to infer T for the
?? operator. It successfully infers T == Int32, because
the expression a?.x has the type Int32?.
it is okay for ?? to return Int32 here, because Int has an initialiser that takes Int32.
most relevantly, the literal -1 can be converted to Int32, because Int32 conforms to ExpressibleByIntegerLiteral.
If you instead do Int(a?.x ?? CONSTANT), however, that last point wouldn't work. ExpressibleByIntegerLiteral only works with literals, not any constant. The compiler sees CONSTANT as an expression of type Int, and tries very hard to find a type for the expression a?.x ?? CONSTANT, but it can't, and spits out a not-so-useful error message.
I suppose the error message is not very useful because it needs to consider quite a lot of things in this case (return type, the two parameters, overload resolution for Int.init), and it could be rather hard to pinpoint exactly where went wrong.
Anyway, to fix this, you can just convert the constant to Int32:
Int(a?.x ?? Int32(CONSTANT))
Or if you don't want to convert CONSTANT to an Int32 then back to Int again, you can rewrite this as:
a.map { Int($0.x) } ?? CONSTANT
"Map a to its x as an Int if a is not nil, otherwise CONSTANT".
)
I have updated a "Workout Object" to have both a minimum and maximum number of reps.
When I've been hardcoding the lower bound in a playground, I've been using :
let numberOfExercises = Int(arc4random_uniform(4) + 3)
When I try to use variables in a function/with a class object I get an error of "+'is unavailable: Please use explicit type conversions or Strideable methods for mixed-type arithmetics" e.g. here ...
class ExerciseGeneratorObject: Object {
#objc dynamic var name = ""
#objc dynamic var minReps = 0
#objc dynamic var maxReps = 0
convenience init(name: String, minReps: Int, maxReps: Int) {
self.init()
self.name = name
self.minReps = minReps
self.maxReps = maxReps
}
func generateExercise() -> WorkoutExercise {
return WorkoutExercise(
name: name,
//get error on this line...
reps: Int(arc4random_uniform(UInt32(maxReps))+minReps)
)
}
}
There is an answer here + is unavailable: Please use explicit type conversions or Strideable methods for mixed-type arithmetics but that method is already using so don't see how it's applicable here.
Also here '+' is deprecated: Mixed-type addition is deprecated in Swift 3.1 but again think this is a different problem
'+' is unavailable: Please use explicit type conversions or Strideable methods for mixed-type arithmetics.
Example:
let a: UInt32 = 4
let b = 3
let result = a + b //error
Basically means you can't add mixed-types.
In your case when you do arc4random_uniform(UInt32(maxReps)) + minReps, arc4random_uniform() returns a UInt32 which cannot be added to minReps because that's an Int.
Solution:
Update your parenthesis:
let numberOfExercises = Int(arc4random_uniform(UInt32(maxReps))) + minReps
Here Int(arc4random_uniform(UInt32(maxReps))) gives an Int that we can add to the minReps Int.
BTW, the following works out-of-the-box:
let numberOfExercises = Int(arc4random_uniform(4) + 3)
Because of Swift's automatic type inference. Basically it just went ahead with UInt32 without bothering you. That is... until you give it explicit mixed types.
I have a problem with a closure that is meant to be created and then being executed within another function over the range of the 2D pixel raster of an image where it shall basically called like this:
filter(i,j) and return a value based on its arguments.
I thought this code should work but it complains that the closure variable I have created is not initialized. I guess that means that I did not gave it arguments, but I wont within this function as the data is known to the closure at the time when it interacts with the image. How can I setup a closure which does not care about initialization?
Thank you in advance :)
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var closure:(i:Int, j:Int)->Int
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
closure = filter
}
//other if statements with different closure definitions follow...
//This call throws error: variable used before being initialized
let image = filterImage(closure)
}
You use the variable closure before the compiler is certain that it is initialized. You can solve this in 2 ways, depending on what you need:
Add an else-clause to your if and set closure to a default closure.
Make closure optional by defining it as var closure: ((i: Int, j: Int) -> Int)? and then you can check if it is optional before using it by using closure?(i, j) or if let filter = closure { filter(i, j)}.
Also, try to use better variable names such as filterClosure. closure on its own doesn't really say much.
The problem is that you define your closure as:
var closure:(i:Int, j:Int)->Int
Then you initialize it only if you enter the if
If not, that var is not initialized, hence the compiler warning
Possible solution:
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var filterClosure:((i:Int, j:Int)->Int)?
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
filterClosure = filter
}
//other if statements with different closure definitions follow...
if let closure = filterClosure {
let image = filterImage(closure)
}
}
Your closure is only initialized if the code enters your if block (i.e. if type == FilterType.MyFilter). In the other case it is left uninitialized.
I made a new Playground and wrote the code as following.
var value = 33 //This will make an integer type of value variable with value 33
value = 22.44 //This doesn't execute as its assigning Double/Float value to an integer.
I tried
1.
value = Double(value)
value = 44.55 //Error here
2.
value = Double(33.44) //Error here too.
3.
value : Double = 33.22 //Error here too.
Now what should I do to assign floating point to value.
NOTE: I am at learning level in Swift.
Thanks.
Declaring var value = 33 will infer the type of value as Int. If you want to assign 33 and make value as Float or Double, you have to declare the type var value : Double = 33 or convert 33 to a Double while assign var value = Double(33).
You must set the data type within the variable declaration.
var value: Double = 33
But you could also do it like so:
var value: Double
value = 33
Defining it as a var will make the variable mutable, so after defining you can change the value
value = 33.2
value = 46.1
If you are only defining a constant, or a variable which does not need to change, you're best defining it like so:
let value: Double = 33.2
If you need this to be an Int for any reason at some point you can pass it through to a function or define it like so:
let intValue = Int(value)
With the first line
var value = 33
you created a variable with the type of Int (because 33 is an integer literal). After that, you cannot assign any other type to that, only Ints. You should create another variable to store the result of the convertion.
I am newbie on Swift.
I am trying to learn basics and structure. I have started a project, i am learning as i advance.
fatal error: unexpectedly found nil while unwrapping an Optional value
I am taking the exception above a few times while coding.
Although I have read the Apple documentation, my mind is not clear.
Could anyone tell the story about this exception and its causes, how is related with Optional on Swift?
Thanks
Code is as below
var globalDaily:Float = 0.0
for var i=0; i<favoritesArray.count; ++i {
var tempDict:NSMutableDictionary = favoritesArray.objectAtIndex(i) as NSMutableDictionary
let tempFloat:Float! = tempDict.objectForKey("amount") as? Float
globalDaily = globalDaily + tempFloat//This line gives the bad access
}
In swift a variable must always contain a valid value. For value types (int, float, strings, structs, etc.) it means the variable must be initialized. For reference types (instance of classes) they must be initialized to a valid instance of a class and cannot be nil.
In swift a variable cannot be left uninitialized. But there are cases when it is allowed for a variable to be non initialized or initialized with nil. This is why the concept of optionals has been introduced. An optional variable can contain a valid value for its data type, or nil. An optional variable is declared by postfixing the question mark to the type, for instance: var x = Int?.
Suggested reading: Optionals in the Swift Programming Language book.
As for your problem, here:
let tempFloat:Float! = tempDict.objectForKey("amount") as? Float
you read a value from a dictionary, which can be nil if no value has been set for the amount key. That's why there is a cast as? Float. That casts to an optional type, which can either contain a valid Float type, or nil.
In the left side of the assignment let tempFloat:Float! you are stating that the right side is not nil (by using the exclamation mark), and that you can use tempFloat without unwrapping it.
If the dictionary contains a valid float for the amount key, then that's not a problem. But if the dictionary doesn't contain a value, what happens is that a nil is attempted to be converted to a Float when you try to use the tempFloat variable - which causes the exception.
The workaround looks like this:
let tempFloat = tempDict.objectForKey("amount") as? Float
if let unwrappedFloat = tempFloat {
globalDaily = globalDaily + unwrappedFloat
}
this makes sure that you use the variable (and do the addition) only if tempFloat contains a valid float value.
I think you can use downcasting to Float only if Dictionary has AnyObject type
See example:
var globalDaily:Float = 0.0
var favoritesArray:Array<Dictionary<String,AnyObject>> = []
var item:Dictionary<String,AnyObject> = ["amount": 2.0]
favoritesArray.append(item)
for var i=0; i<favoritesArray.count; ++i{
var tempDict:Dictionary = favoritesArray[i]
if let tempFloat:Float = tempDict["amount"] as AnyObject! as Float!{
globalDaily = globalDaily + tempFloat // output 2
}
else{
globalDaily = globalDaily + 5
}
But if the key doesn't exist, we get 5
So if you know that you have Float type only, you can write just:
var globalDaily:Float = 0.0
var favoritesArray:Array<Dictionary<String,Float>> = []
var item:Dictionary<String,Float> = ["amount": 2.0]
favoritesArray.append(item)
for var i=0; i<favoritesArray.count; ++i{
var tempDict:Dictionary = favoritesArray[i]
if let tempFloat:Float = tempDict["amount"]{
globalDaily = globalDaily + tempFloat
}
else{
globalDaily = globalDaily + 5
}