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

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"]

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!

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.

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.

<unknown>:0: error: type 'Key' constrained to non-protocol type 'String'

Migrating to Swift 3 from 2.3 and am running into this issue. The error is traceable to a view controller.
I do not see any extensions/protocols which would require a 'Key' constrained to 'String'.
I've tried to comment out code that might be causing the error, and have had strange results - ie removing an empty viewDidLoad() made the error appear in another class.
I'll update the thread if I make progress.
Key is a type inside a structure maybe a struct/class like Dictionary.
Use AnyHashable as Key to replace String if in Dictionary.

Cannot pass dictionary to function in 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.