Error: Argument type double/string etc. does not conform to expected type "AnyObject" - swift

I watched some iOS programming tutorial and have a question on "AnyObject".
The bridging does not work.
I have the following code:
import Foundation
class CalculatorBrain
{
private var accumulator = 0.0
var internalProgram = [AnyObject]()
func setOperand (operand: Double) {
accumulator = operand
internalProgram.append(operand)
}
// ...
}
Same for string...
func performOperation (symbol: String) {
internalProgram.append(symbol)
}
I know about NSString and the reference type vs. struct thing, and that double and string are no reference types.
But anyway in the tutorial the bridging worked fine...
What could be the reason for my failure?

As you correctly say, Double and String are not reference types in Swift – they are structs. Therefore you cannot directly store them in an [AnyObject], you would first need to bridge them to Objective-C in order to do so.
Although bridging to Objective-C in this case is unnecessary – if you want an array of heterogenous types, including value types, then you can use an [Any]:
var internalProgram = [Any]()
However, from what I can tell, you don't want a array of anything (it's very rarely a good idea) – you just want an array that can contain a Double or a String.
You can describe this with an enum:
enum OperationArgument { // feel free to give me a better name
case operand(Double)
case symbol(String)
}
And now you can define an array of it:
var internalProgram = [OperationArgument]()
func setOperand (operand: Double) {
internalProgram.append(.operand(operand))
}
func performOperation (symbol: String) {
internalProgram.append(.symbol(symbol))
}
Now instead of conditional type-casting to get back the type of each element, you can just use a switch or an if case:
for element in internalProgram {
switch element {
case let .operand(operand):
print(operand)
case let .symbol(symbol):
print(symbol)
}
if case let .operand(operand) = element {
print(operand)
}
}

To use a Swift value type as an AnyObject, in Swift 3 you need to explicitly cast it to the old Objective-C object type.
So this
internalProgram.append(operand)
becomes this
internalProgram.append(operand as NSNumber)
And this
internalProgram.append(symbol)
becomes this
internalProgram.append(symbol as NSString)
The tutorial you are talking about has probably been written with Swift 2 where you just needed to import Foundation.

var internalProgram = [AnyObject]()
func setOperand (operand: Double) {
// you have cast operand as AnyObject !!
internalProgram.append(operand as AnyObject)
}
setOperand(operand: 10)
print(internalProgram, type(of: internalProgram)) // [10] Array<AnyObject>

Related

Accessing swift dictionary members using AnyObject

I'm having trouble with understanding how to properly do unwrapping in Swift. Here is the situation:
I have these two classes:
class Alpha
{
var val: Int
init(x: Int)
{
val = x
}
func doSomething() -> Int
{
// does stuff and returns an Int value
return val
}
}
and a second class which is a subclass of the first
class Beta: Alpha
{
var str: [String] = []
override init(x: Int)
{
super.init(x)
}
func doSomething() -> String
{
// does stuff and returns a String
return str
}
}
So far so good, these two classes work as expected. But now I want to create a dictionary to store several of both these class objects. So I've created a class to manage the dictionary and add items to it.
class Gamma
{
var myDict: [String:AnyObject] = [:]
func addAlphaToDict(key: String, val: Int)
{
self.myDict[key] = Alpha(x: val).self
}
func addBetaToDict(key: String, val: Int)
{
self.myDict[key] = Beta(x: val).self
}
}
This also is working, but I think this could somehow be improved. The issue I'm having is now when I try to access values in the dictionary:
var foo = Gamma()
foo.addAlphaToDict(key: "blah", val: 45)
foo.addBetaToDict(key: "bluh", val: 23)
var result1 = (foo.myDict["blah"] as! Alpha).doSomething()
var result2 = (foo.myDict["bluh"] as! Beta).doSomething()
I find that the syntax here is very clunky and I feel like I'm doing it wrong, even though it works. I'm an experienced developer, but have only just started using Swift so I'm not really sure about certain things. Could someone with more Swift experience show me how to improve this code, or point me in the direction I should be going? Thanks!
You can use Alpha instead of AnyObject as your dictionary value in this case. Just downcast it to Beta when needed. Using AnyObject or Any as the dictionary key should be avoided as much as possible.
However, i have to say that this approach is bad. You need to have a clearer logic to decide when the key will be Beta other than just relaying on knowing which key you are passing to the dictionary.
In swift when you want a heterogeneous type with a finite number of possibilities, prefer an enum with associated values to Any or AnyObject. You can then use a switch to recover the type in an exhaustive and type safe way.
import UIKit
import PlaygroundSupport
enum DictionaryValues {
case integer(Int), string(String)
}
let dictionary: [String: DictionaryValues] = ["a": .integer(1), "b": .string("xyz")]
for (key, value) in dictionary {
switch value {
case .integer(let number):
print("Key \(key) is a number: \(number)")
case .string(let text):
print("Key \(key) is text: \(text)")
}
}

Extension on Array where Element is generic not compiling [duplicate]

It is legal to say this (arr is an Array):
let arrenum = Array(arr.enumerated())
So why isn't it legal to say this?
extension Array {
func f() {
let arrenum = Array(self.enumerated())
// error: type of expression is ambiguous without more context
}
}
EDIT It seems this is a workaround:
extension Array {
func f() {
typealias Tup = (offset:Index, element:Element)
let arrenum = Array<Tup>(self.enumerated())
}
}
But why is that needed? (And is it right?)
This is a known bug (SR-1789). Swift currently has a feature where you can refer to a generic type within its own body without having to repeat its placeholder type(s) – the compiler will infer them for you to be the same as the type of self.
For example:
struct S<T> {
func foo(_ other: S) { // parameter inferred to be `S<T>`.
let x = S() // `x` inferred to be `S<T>`.
}
}
extension S {
func bar(_ other: S) {} // same in extensions too.
}
This is pretty convenient, but the bug you're running into is the fact that Swift will always make this inference, even if it's incorrect.
So, in your example:
extension Array {
func f() {
let arrenum = Array(self.enumerated())
// error: type of expression is ambiguous without more context
}
}
Swift interprets the code as let arrenum = Array<Element>(self.enumerated()), as you're in the body of Array<Element>. This is incorrect, because enumerated() yields a sequence of offset-element tuple pairs – Swift should have inferred Array to be Array<(offset: Int, element: Element)> instead.
One workaround, which you've already discovered, is to explicitly specify the placeholder type in order to prevent the compiler from making this incorrect inference.
extension Array {
func f() {
let arrenum = Array<(offset: Int, element: Element)>(self.enumerated())
}
}
Another possible workaround appears to be using the fully-qualified type, for example:
extension Array {
func f() {
let arrenum = Swift.Array(self.enumerated())
}
}
as it appears Swift doesn't do the same inference for fully-qualified types (I'm not sure if you should rely on this fact though).
Finally it's worth noting that instead of doing a call to Array's initialiser, you could use map(_:) instead to avoid the issue entirely:
extension Array {
func f() {
let arrenum = self.enumerated().map { $0 }
}
}
which, like the initialiser call, will give you back an array of offset-element pairs.

Can you overload type-casting operators in Swift?

I'd like to implement automatic type conversions between known types in Swift. The C# way of doing it has been overloading type-casting operators. If I want my X type to be cross-assignable with, say, string, I would write:
public class X
{
public static implicit operator string(X value)
{
return value.ToString();
}
public static implicit operator X(string value)
{
return new X(value);
}
}
After that I could write stuff like:
string s = new X();
X myObj = s;
and they would be automatically converted. Is that possible in any way in Swift?
No, the language doesn't provide such functionality for custom types. There is bridging between Objective-C collections and Swift collections but that's baked in and not customizable.
// Swift array of `String` elements
let swiftArray: [String] = ["Bob", "John"]
// Obj-C array of `NSString` elements, but element type information
// is not known to the compiler, so it behaves like an opaque NSArray
let nsArray: NSArray = ["Kate", "Betty"]
// Obj-C array of an `NSString` and an `NSNumber`, element type
// information is not known to the compiler
let heterogeneousNSArray: NSArray = ["World", 3]
// Casting with `as` is enough since we're going from Swift array to NSArray
let castedNSArray: NSArray = swiftArray as NSArray
// Force casting with `as!` is required as element type information
// of Obj-C array can not be known at compile time
let castedSwiftArray: [String] = nsArray as! [String]
// Obj-C arrays can not contain primitive data types and can only
// contain objects, so we can cast with `as` without requiring a
// force-cast with `!` if we want to cast to [AnyObject]
let heterogeneousCastedNSArray: [AnyObject] = heterogeneousNSArray as [AnyObject]
Documentation for type casting is available here.
I think you can achieve what you want to do with initializers.
extension X {
init(string: String) {
self = X(string)
}
}
extension String {
init(x: X) {
// toString is implemented elsewhere
self = x.toString
}
}
let x = X()
let string = "Bobby"
let xFromString: X = X(string: string)
let stringFromX: String = String(x: x)
Not directly related to your question but there is also a family of protocols that start with ExpressibleBy..., enabling you to do things like the following:
Let's say we want to initialize strings from integer literals. We can do that by conforming to and implementing ExpressibleByIntegerLiteral
// Strings can not be initialized directly from integer literals
let s1: String = 3 // Error: Can not convert value of type 'Int' to specified type 'String'
// Conform to `ExpressibleByIntegerLiteral` and implement it
extension String: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
// String has an initializer that takes an Int, we can use that to
// create a string
self = String(value)
}
}
// No error, s2 is the string "4"
let s2: String = 4
A nice use case for ExpressibleByStringLiteral can be found here.

Conversion operator in swift

Is it possible to write custom conversion (casting) operator in swift? Especially I'm looking for enums conversion, ex:
enum MyEnum : Int {
case Case1 = 0
case Case2
func __conversion() -> String { // doesn't work since Swift 1.0
switch self {
case Case1: return "Case 1"
case Case2: return "Case 2"
}
}
}
let enumStr: String = MyEnum.Case1
Of course, I can convert to String with explicit method, but I would like to have implicit mechanism.
Disclaimer/TL;DR! This answer pertains to the technical question as to whether we can possibly implement implicit bridging mechanisms between different Swift types ourself. The answer is: for some cases, yes, but only in a limited sense and by means of "hacks": do not use this is production code!
Swift internal protocol abuse: we may implement implicit mechanisms to Obj-C objects (e.g. NSNumber, NSString ...)
As MartinR writes in his comment, custom conversion methods are not present for (native) Swift.
For the technical discussion we can, however, (ab)use the internal protocol _ObjectiveCBridgeable to allow implicit bridging from your enum to Obj-C objects, in this case e.g. NSString. For a more detailed Q&A of the subject of the internal protocol _ObjectiveCBridgeable, see
Is it possible to replicate Swifts automatic numeric value bridging to Foundation (NSNumber) for (U)Int8/16/32/64 types?
Before proceeding, I'll quote a disclaimer from my answer in thread above:
... note that _ObjectiveCBridgeable is an internal/hidden protocol
(_UnderScorePreFixedProtocol), so solutions based on it might break
without warning in upcoming Swift versions.
Example #1: implementing implicit bridging of your enum to NSString
First lets add a failable initializer to your enum, allowing (attempted) initialization by String instances:
import Foundation
enum MyEnum: Int {
case Case1 = 0
case Case2
init?(string: String) {
switch string {
case "Case 1": self = .Case1
case "Case 2": self = .Case2
default: return nil
}
}
}
Next up, let MyEnum conform to _ObjectiveCBridgeable, as described in more detail in the thread linked to above
extension MyEnum: _ObjectiveCBridgeable {
typealias _ObjectiveCType = NSString
static func _isBridgedToObjectiveC() -> Bool {
return true
}
static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
func _bridgeToObjectiveC() -> _ObjectiveCType {
return NSString(string: "Case \(self.rawValue+1)")
}
static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) {
result = MyEnum(string: source as String)
}
static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool {
self._forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
With the conformance above, we can now make use of implicit bridging from MyEnum instances to NSString
/* example usage */
var myCase: MyEnum = .Case1
var enumNSstr: NSString = myCase // MyEnum -> NSString, implicit
print(enumNSstr) // Case 1
enumNSstr = "Case 2"
// NSString -> MyEnum, by type conversion (castable)
myCase = (enumNSstr as MyEnum) ?? .Case1
print(myCase) // Case 2
Example #2: implementing implicit bridging of your enum to a custom Swift native type
We may even abuse the _ObjectiveCBridgeable protocol further, using its (deep backend) mechanisms to implement implicit bridging between two native Swift types, with the limitation that the type bridged to must be a reference type (specifically: instances of the type must be representable by AnyObject, hence the reference type limitation).
Let MyEnum be as defined above, but additionally, define a reference (class) type Foo, and conform MyEnum to _ObjectiveCBridgeable with the bridged to type, _ObjectiveCType being set to Foo.
class Foo {
var bar: String
init(bar: String) { self.bar = bar }
}
extension MyEnum: _ObjectiveCBridgeable {
typealias _ObjectiveCType = Foo
static func _isBridgedToObjectiveC() -> Bool {
return true
}
static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
func _bridgeToObjectiveC() -> _ObjectiveCType {
return Foo(bar: "Case \(self.rawValue+1)")
}
static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) {
result = MyEnum(string: source.bar)
}
static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool {
self._forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
We can now make use of implicit bridging from MyEnum instances to Foo
/* example usage */
var myCase: MyEnum = .Case1
var myFoo: Foo = myCase // MyEnum -> Foo, implicit
print(myFoo.bar) // Case 1
myFoo.bar = "Case 2"
// Foo -> MyEnum, by type conversion (castable)
myCase = (myFoo as? MyEnum) ?? .Case1
print(myCase) // Case 2
Finally note that you may, for any given type (say, MyEnum), naturally only implement implicit bridging to a single other (reference) type; since you can only conform to _ObjectiveCType once (for a unique type for the typealias _ObjectiveCType), otherwise yielding a compile time error for redundant protocol conformance.
The above is tested for Swift 2.2.

Why doesn't swift infer the appropriate overload function with a generic return argument without a type constraint?

Note
Swift is changing rapidly, this question was asked regarding:
Xcode 7, Swift 2.0
Explanation
I'm looking to implement a generic return argument. Quite often, I find it necessary to implement an optional version overload so I can access the underlying type and handle it appropriately. Here's some manufactured functions. The assignment of String is just there as a placeholder for replication:
func ambiguous<T>() -> T {
let thing = "asdf"
return thing as! T
}
func ambiguous<T>() -> T? {
return nil
}
Now, if we look at the implementation:
// Fine
let a: String = ambiguous()
// Ambiguous
let b: String? = ambiguous()
This might seem obvious because you could assign type T to a variable of type T?. So it makes sense that it would have trouble inferring. The problem is, that with a type constraint, it suddenly works. (This can be anything, I'm using Equatable for easy replication.
func nonAmbiguous<T : Equatable>() -> T {
let thing: AnyObject = "asdf"
return thing as! T
}
func nonAmbiguous<T : Equatable>() -> T? {
return nil
}
And now, it functions as expected:
// Fine
let c: String = nonAmbiguous()
// Fine
let d: String? = nonAmbiguous()
Note, this also works with other type:
func nonAmbiguous<T>() -> [T] {
let thing: AnyObject = ["asdf"]
return thing as! [T]
}
func nonAmbiguous<T>() -> [T]? {
return nil
}
// Fine
let e: [String] = nonAmbiguous()
// Fine
let d: [String]? = nonAmbiguous()
Question:
Is there a way to have a return generic argument infer the appropriate overload through optionality?
if no
Is this a language feature, or a bug somewhere. If it's a language feature, please explain the underlying issue preventing the possibility of this behavior.
The first example is ambiguous because T can be inferred as both String
and String?.
The second example is not ambiguous because String is Equatable but String? is not, so T : Equatable cannot be inferred as String?.
The third case is not ambiguous because [T] is not
inferred as [String]?.
Remark: Generally, Optional<Wrapped> does not conform to Equatable
even if Wrapped does, in the same way as Array<Element>
does not conform to Equatable even if Element does.
This is a restriction of the current type system in Swift which
might be improved in a future version, compare
[swift-dev] RFC: Adding Optional variants of == for collections to the std lib.
from the Swift development mailing list.