Difference between wrapping a value and explicitly declaring value as a type in Swift - 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!

Related

what's the difference between typing String() and String.self in swift?

I'm kind of stuck trying to understand .self in swift, always I register a custom cell in an collectionView or an tableView I have to register like customCollectionViewCell.self but why not for example customCollectionViewCell() ?
I've tried in the playground to type String.self in a var to see what happens and it give me no errors but when I try to give it a value it give me the following error
Cannot assign value of type 'String' to type String.Type
what does it mean?
Type() is shorthand notation for Type.init(), so String() calls String.init() and hence initialises a String.
On the other hand, String.self returns the meta type of String, which is a type that represents the String type itself rather than any instance of that type. For more information on meta types, see the Metatype Type section of the official Swift language reference.
In your specific example, you need to register a UITableViewCell subclass type rather than an instance of a specific type, hence you need to use YourCellType.self.

Realm lazy results type-erasure

I'm working on an iOS app with Realm as the database and I'm confronted to a problem I can't fix without your help.
I have a function that queries objects from my Realm instance like so:
static func trainings(containing exercise: Exercise) -> Results<Training>? {
return Realm.workoutDatabase?.objects(TrainingEntry.self)
.filter({ $0.exercise == exercise })
.compactMap({ $0.training })
}
This code produces the following error:
Cannot convert return expression of type 'LazyMapCollection<LazyFilterCollection<LazyMapCollection<LazyFilterCollection<Results<TrainingEntry>>, Training?>>, Training>?' to return type 'Results?'`
There error is obviously that the return type should not be Results<Training>? but LazyMapCollection<LazyFilterCollection<LazyMapCollection<LazyFilterCollection<Results<TrainingEntry>>, Training?>>, Training>?.
Outch! That type is soooooo long.
I tried to set [Training]? as the return type for the function and it worked.
But by doing so, I'm afraid that this will implicitly cast the returned result of the expression into an array, thus loosing the laziness of the collection?
As far I as know, I need a type-eraser to get a much shorter type, but I'm definitely not an expert on that particular subject.
I know that the Swift Standard Library provides a few type-erasure structs, such as AnyGenerator, AnySequence but I'm afraid I don't know enough about type-erasure to use them in my case.
So my question is, how to use type-erasure to get a cleaner return type for my function?
Edit:
I tried to cast the expression to AnyRandomAccessCollection but I get the following error:
Type 'LazyFilterCollection<LazyMapCollection<LazyFilterCollection<Results<TrainingEntry>>, Training?>>' does not conform to protocol 'RandomAccessCollection'
I also tried to cast to AnyCollection and AnyBidirectionalCollection, both of them work, but then I'm loosing the ability to subscript with an Int, which is something I want to keep.

Swift: Optional variable in function signature showing error Method cannot be marked #objc because the type

I'm working in swift framework but I need to support ObjC. But I have a function like this:
#objc public func doingSomething(thing:String?,time:Int?)->String{
return result
}
But I'm getting the following error:
Method cannot be marked #objc because the type of the parameter 2 cannot be represented in Objective-C
Any of you knows a work around this error?, or how can I fix this error?
I'll really appreciate your help.
The problem is that integers are a primitive type in Objective-C, so the language is not capable of assigning nil to an integer-typed variable. Therefore, you cannot have Int? in the signature of a method that is exposed to Objective-C.
As a workaround, you can either make the parameter an Int and define a sentinel value to represent a nil value (NSNotFound is an example found in the various "indexOf" methods in the frameworks; 0 may work in some cases), or else you can type the parameter as an NSNumber? since NSNumber is an object type and thus can be nil.

How to observe key path on 'Any' object in Swift 4

I'm using the new Swift 4 KVO and KeyPath APIs to observe changes on an object. Specifically I'm trying to observe something on the selection object of an NSArrayController. The problem is the selection is of type Any and that seems to be at odds with generating the required keypath, since the compiler doesn't know of any properties on an object of type Any.
The property's name is assetPointHeight. And my code looks like this:
var observation: NSKeyValueObservation?
observation = arrayController.observe(
#keyPath(NSArrayController.selection.assetPointHeight),
options: [.new],
changeHandler: { [weak self] (_, _) in
self?.updateLabel()
}
)
I get two compile errors:
Generic parameter Value could not be inferred
Type 'Any' has no member 'assetPointHeight'
How can I achieve what I'm looking for here? Is there another way of generating this KeyPath?
I would not expect this to work because assetPointHeight isn’t a real property on selection (eg, it’s not defined anywhere in source code, it’s a virtual property created at runtime). I think what’s happening here is the Swift 4 version of observe(...) is trying to resolve that path to a static type and cannot, so it’s throwing an error. (Observing only works on NSObject subclasses, as well, so Any could never be observed.) So in this case you would have to use traditional string-based KVO, as “vadian” said.

Cast to a Metatype Type in Swift?

Can you cast to a Metatype Type in Swift? It really seems like you should be able to (after all you can instantiate objects from Metatypes).
The following doesn't work:
class Super {}
class A : Super {}
let superA:Super = A()
let subType = superA.dynamicType
let afterCast = superA as subType
//Compiler error: "use of undeclared type 'subType'"
Does anyone know the right way to do this?
Edit:
As newacct pointed out, the result of .dynamicType is obviously not known until runtime, so a compile-time cast to the result of .dynamicType would not make sense.
So the answer is: "You can't" (and there is no good reason to try).
First of all, as takes a type, not an expression, on the right-hand side. So what you have is a syntax error.
What you seem to be trying to do is "cast" to a type that is computed at runtime. What would that even mean? Let's first consider what is a "cast".
Usually, when we have a cast expression x as T, it has two components:
At compile-time: The entire cast expression x as T has compile-time type T?, which allows you to do stuff with the resulting expression that you maybe cannot do on x directly. In other words, it allows you to change the compile-time type.
At runtime: It checks whether the runtime type of x is a subtype of T, and if it is, it evaluates to the optional containing that value, otherwise, it evaluates to nil.
If the type T is not known at compile-time, then obviously you cannot do the compile-time part of it. (The compile-time type of the resulting expression cannot, obviously, depend on something which is not known at compile-time.)
The other part, the runtime component, could that be done with a type computed at runtime? Sure. For example,
import Foundation
let afterCast : Super? =
(superA as AnyObject).isKindOfClass(subType) ? superA : nil
It's not clear if that is what you want.