Cannot pass dictionary to function in swift - swift

Tearing my hair out on this one.
I'm trying to pass a dictionary of type [String:UIView] to a function in swift that's expecting a [NSObject:AnyObject] :
NOTE: I get the exact same error if I use NSString instead of String:
Any ideas what I'm doing wrong?
opponentImageView is a UIImageView....
PROBLEM RESOLVED
turns out the issue was actually with the 'options' argument being passed 0. Passing NSLayoutFormatOptions(0) made this misleading error go away. Here is what the code now looks like:
It builds fine now...

There is some problem when you try to cast String as NSObject implicitly in pure swift class. You need to define it explicitly
let viewsDict:[NSObject:AnyObject] = ["yourview":view]
and there is one error more options can not be 0.So define options as proper NSLayoutFormatOptions type.

Related

Difference between wrapping a value and explicitly declaring value as a type in Swift

I came across a heterogeneous dictionary definition like this on a tutorial online:
var mixedMap4 = [AnyHashable(0): "Zero" as Any,
AnyHashable(1): 1.0 as Any,
AnyHashable("pi"): 3.14 as Any]
I was wondering why the author chose to write
AnyHashable(0) instead of 0 as AnyHashable. When I tried this on Swift playground, it also worked. However when I turned "Zero" as Any into Any(0) it gives the following
error: error: The Dictionary.xcplaygroundpage:41:34: error: protocol
type 'Any' cannot be instantiated var mixedMap4 = [AnyHashable(0):
Any("Zero") ,
Thank you for the answer
The clue is in the error message.
AnyHashable is a struct that type-erases the underlying hashable type, and so can be directly instantiated as an object
Any is a protocol and therefore can't be directly instantiated, although all other types can be complied with it, thus a String such as "Zero" can be cast as Any but Any(String) is meaningless.
To me it all just feels like a bucket load of trouble waiting to happen!

Dynamic casting using result of NSClassFromString("MyUIViewController")

I'm finding that the following code does not work, but I don't exactly understand why.
Say I have a class name saved in a string. I want to cast a view controller as the class that this string refers to.
let controller = self.navigationController as! NSClassFromString("MyUIViewController")
Swift doesn't seem to understand this - I get this error:
Undeclared use of NSClassFromString.
Or the error:
Consecutive statements must be separated by `,`
Can anyone explain why this is the case? I can't cast (using as?) a type based on some variable?
Thanks
No, you cannot cast to a runtime type object. You must cast to a compile-time type. This is why we write x as Int, not x as Int.self: Int is a type, and Int.self is an object that represents that type at runtime.
What would it mean to cast to NSClassFromString("MyUIViewController")? Now you have a variable, controller, whose value is some type that the compiler knows nothing about, so the compiler cannot let you do anything with controller. You can't call methods or access properties on it, because the compiler doesn't know what methods or properties it has. You can't pass it as an argument to a function, because the compiler doesn't know whether it is the right type for that argument.
If you edit your question to explain what you want to do with controller (what methods you want to call on it or what properties you want to access or what functions you want to pass it to), then I will revise my answer to address your goal.

Expression Type 'Set<NSObject>' is ambiguous without more Context

I recently switched to Swift 3 and I got an error with the following line that I didn't get in swift 2. The layerClient call refers to the layerkit api, but the error seems to deal more with typing than the api. The error itself is "Expression Type 'Set' is ambiguous without more ".
layerClient.autodownloadMIMETypes = Set<NSObject>(arrayLiteral: "image/png")
I assume you're using this framework.
You don't need the <NSObject> when creating the Set. It can figure out with type it contains by the parameter you pass to the init method. Also autodownloadMIMETypes type in swift would be Set<String> which wouldnt match Set<NSObject>. This should work.
layerClient.autodownloadMIMETypes = Set(arrayLiteral: "image/png")
Also, since Set conforms to the ExpressibleByArrayLiteral protocol, you should be able to just create it like an array.
layerClient.autodownloadMIMETypes = ["image/png"]

Swift. When should you define an Object / Value with specific data type

As I started developing with Swift and searching through different tutorials and documentations about the language, I'm not sure about one thing.
You can declare an object / value with a specific data type like this:
var aString:String = "Test"
var anObject:SKScene = ASceneClass()
Or you can just do it like this:
var aString = "Test"
var anObject = ASceneClass()
The result will be exactly the same (ASceneClass inherits from SKScene of course)
As everyone is doing it different I wonder if there's a logical reason behind it or you do it for readability ?
Declaring type right after variable name is called Type Annotation
When you don't do that, you have to provide initial value
var aString = "Test"
Often value is not known at that moment, or you are not even sure if it's going to be not nil value, then you can declare it as optional
var aString:String?
If you would like to declare variable without any initiaization but you are sure it's not going to evaluate to nil, you force unwrap it
var aString:String!
This is the definition. In practice, it's always better to use type annotations even when you initialize variable with value, because later in your program you will notice anytime you mess something with the type of the variable.
Also, When you declare an array or dictionary, usually nested ones, Xcode might expect them to have type annotations since it might have some issues with writing values when the type is not known in advance.
To recap
You will want to use type annotations whenever you can, which means whenever you are sure about the variable's type in advance
Recommended/Documented way to declare a variable in swift is as follow:
var <variable name>: <type> = <initial value/expression>
Note: Given form declares a stored variable or stored variable property. Its used when you are clear about type annotation of it.
Though its valid to declare variable without its Type.
var variableName = <initial value>
Note: When you don't know type annotation its mandatory to assign 'Initial value' to that variable.
Refer Swift Documentation on Declaration for more details.

Swift 1.2 cannot invoke 'count' with an argument list of type '(String)'

Updated to Xcode 6.3.1 with new Swift 1.2, the old method countElement change to count, however when I switch to use count, it always throw out this error message:
cannot invoke 'count' with an argument list of type '(String)'
This snippet is I copied from Apple doc, but still not working.
func printAndCount(stringToPrint: String) -> Int {
println(stringToPrint)
return count(stringToPrint)
}
func printWithoutCounting(stringToPrint: String) {
printAndCount(stringToPrint)
}
printAndCount("hello, world")
Try calling the global count function with the Swift module prefix like this:
Swift.count(stringToPoint)
E.g. when extending the Array type there is a property named count as well and thus there is a naming conflict.
Did you declare the variable "count" in the same scope?
If so, you should change the variable name. And try to build again.
I had the same problem and it was making me crazy.
To solve it, I used:
myString.characters.count
Bingo.
Have you tried a clean and build? It works here.
Well, I create a new playground and copy the code works fine. I guess it's because the previous playground swift version messed up. Create a new project works fine.