How to fix 'Int' is not convertible to 'String' in a comparison that uses only Int? - swift

Imagine my surprise that this Swift code generates an error in Xcode 6.1.1:
public func unlockNextLevel() -> Int
{
var highest : Int = 123
return (highest < highestUnlockedLevel)
}
More precisely, it tells me that in the return line:
'Int' is not convertible to 'String'
So, since I had some of these weird conversion errors before, I thought I'll try converting both types to Int and see what I get:
public func unlockNextLevel() -> Int
{
var highest : Int = 123
return (Int(highest) < Int(highestUnlockedLevel))
}
I then get the following error on the return line:
Could not find an overload for '<' that accepts the supplied arguments
But when I break it down to just constant values:
return (Int(3) < Int(12))
I get the int not convertible to string error again.
'Int' is not convertible to 'String'
Gnnnnn.... oh-kay, so I give it another shot without the brackets:
return highest < highestUnlockedLevel
This then gives me yet another error message:
Cannot invoke '<' with an argument list of type '(#lvalue Int, #lvalue Int)'
Okay, I get it Swift, I'm stoopid. Or maybe ... hmmm, take this, Swift:
var result = highest < highestUnlockedLevel
return result
Arrrr ... nope. Swift decides that now the return line constitutes yet another error:
'Bool' is not convertible to 'Int'
(... dials number for psych evaluation ...)
So ... could someone explain to me:
how to fix or work around this issue?
and of course: Why?? Oh, why???
Note: This is in a mixed Objc/Swift project if that makes any difference. The highestUnlockedLevel variable is declared in a Swift class with custom setter and getter.

(highest < highestUnlockedLevel) produces Bool not Int (unlike Objective-C where it returns int that can be automatically converted to BOOL), thats why you get the error. But certainly its wrong and misleading error as the problem is that Bool cannot be converted to Int.

Related

pass a swift var to a C api as void**

I have a C api that looks as follows
struct foo_private_t;
typedef foo_private_t* foo_t;
void foo_func(void**x);
Where the API is intended to be used like this
foo_t x;
void foo_func((void**) &x);
Why the API takes a void** and not a foo_t* is beyond the scope of this question. The problem is when I try to call this API from swift. First I import the C header into swift via the bridging header. Then I try to invoke foo_func with a pointer to a swift object.
var x:foo_t?
foo_func(&x)
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'
That error is expected, I need a pointer to the pointer, so I tried.
withUnsafeMutablePointer(to: x){ x_p in foo_func(x_p) }
// error is cannot convert value of type 'UnsafeMutablePointer<_>' to expected argument type 'UnsafeMutablePointer<UnsafeMutableRawPointer?>!'
This also seems reasonable as x_p is similar to &x, a single level of pointerness. The next attempt I would have expected to work.
withUnsafeMutablePointer(to: x){ x_p in foo_func(&x_p) }
// error is cannot pass immutable value of type 'UnsafeMutableRawPointer?' as inout argument
Searching around for this error reveals that if I was calling a swift function I should use the inout modifier to a parameter. But since I am calling a C api I am not sure that I can make such a modification. How can I pass a pointer that is a mutable value?
If the intention is to pass the address of x to the C function
in a way that foo_func() can assign a new value to x (which
is what the C code
foo_t x;
void foo_func((void**) &x);
does) then it would be:
var x: foo_t?
withUnsafeMutablePointer(to: &x) {
$0.withMemoryRebound(to: UnsafeMutableRawPointer?.self, capacity: 1) {
foo_func($0)
}
}
Inside withUnsafeMutablePointer(), $0 is a
UnsafeMutablePointer<foo_t?>
and this is rebound to a pointer of the expected type
UnsafeMutablePointer<UnsafeMutableRawPointer?>
I was able to get this to work.
var e = UnsafeMutableRawPointer(x)
foo_func(&e)
x is already a pointer, so it can be converted to a raw pointer. Then I need a pointer to that raw pointer, so I take the address of e. I guess I need the e variable because an implicit temporary value cannot be passed as an argument to an inout parameter. E.g.
foo_func(&UnsafeMutableRawPointer(x))
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'

Swift 3: Convert Array<Double> to Array<Float> extension

extension Array where Element : Double {
public var asArrayOfFloat: [Float] {
return self.map { return Float(other:$0) } // compiler error
}
}
I get a compiler error complaining about Float(other:$0) "Argument labels '(other:)' do not match any available overloads." But, $0 is a Double, and there is a Float.init(other:Double) initializer. What's the problem?
EDIT: Changing to Float($0) creates a different compilation error: "Ambiguous use of 'init'", and has 16 candidates.
EDIT: Float.init(other:Double) originally suggested by compiler, snapshot:
The issue was with where Element : Double ... This needs to be rewritten as where Element == Double (notice the use of == instead of :) because Double is not a protocol but a type. Now compilation works with Float($0) as suggested.
Get rid of the other: label. If there is an init override that uses that label (FWIW, I don't see one), then it's not a required label.

swift array Cannot convert value of type 'AnyObject' to expected argument type #noescape(AnyObject) throws - > Bool

let otherArray:[AnyObject] = ["a","aa","aaa"]
let otherArrayElemnt = otherArray[0]
let myArray:[AnyObject] = ["qq"]
if myArray.contains(otherArrayElemnt){ //<<<<<<< Error HERE
//if contains...doSomething
}else{
//none doSomething
}
Error: Cannot convert value of type 'AnyObject' to expected argument type #noscape (AnyObject) throws -> Bool
I don't know how to fix it
String is not an object, so it does not conform to protocol AnyObject. Use Any instead.
Neither AnyObject nor Any is Equatable, so function contains doesn't know how to compare elements of the array with otherArrayElement.
Why do you need to use arrays of Any elements ? Why don't you use arrays of Strings ? What else do you want to store in them ?

Cannot assign value of type 'String' to type 'NSTimeInterval' (aka 'Double')

I'm trying to set my sliders value to the sounds currentValue but then I get this error:
Cannot assign value of type 'String' to type 'NSTimeInterval' (aka 'Double')
I am kind of new to Xcode and errors so I don't really know how to solve this problem but I tried to delete the string part but that did not work.
#IBAction func time(sender: UISlider) {
var timeValue:String = String(Int(sender.value)) sound!.currentTime = timeValue
}
timeValue is a String and currentTime most likely is a NSTimeInterval. You can't assign string to NSTimeInterval. Use Double(sender.value) instead. Also, I would suggest that you do not combine so many operations on one line, especially if you are new to programming or Swift. If you get an error, you don't easily see if the problem was with conversion to String, to Int, if your sound variable was nil or what else is going on.

Swift - 'Bool' is not a subtype of 'Void'?

I'm getting the following error: 'Bool' is not a subtype of 'Void'
performBlock takes a void closure with no argument, and method itself has a single argument, so I should be able to use the following syntax for my closure. Why am i getting this compile error?
workingManagedObjectContext.performBlock {
self.workingManagedObjectContext.save(nil)
self.managedObjectContext.performBlock {
self.managedObjectContext.save(nil)
}
}
The argument to performBlock is a closure taking no arguments and returning Void
(i.e. no return value).
If the closure consists of a single expression, the return type is inferred from
the type of that expression. The type of
self.managedObjectContext.save(nil)
is Bool, which cannot implicitly be converted to Void.
To fix that problem, you can add an explicit return statement:
self.managedObjectContext.performBlock {
self.managedObjectContext.save(nil)
return
}
or (better), check the return value of the save operation instead of ignoring it:
self.managedObjectContext.performBlock {
var error : NSError?
if !self.managedObjectContext.save(&error) {
// report error
}
}
(and do the same for the outer level save).
Update: As of Swift 1.2 (Xcode 6.3), unannotated single-expression closures with non-Void return types can now be used in Void contexts. So this does now compile without errors:
self.managedObjectContext.performBlock {
self.managedObjectContext.save(nil)
// explicit "return" not needed anymore in Swift 1.2
}
(Of course it is still better to actually check the return value
from the save operation.)