How can make a custom extension for Dictionary in Swift? - swift

I am trying to add a function to Dictionary, this func called add, which has 2 input values (key and value). I tried to make the func be generic, that means I want key and value be able take any Type. I end it up to this down non-working code. What I should do next to make this func work?
extension Dictionary {
func add<Key, Value>(key: Key, value: Value) {
self[Key] = Value
}
}

First, you are trying to assign a type instead of an instance to the dictionary.
Type of expression is ambiguous without more context):
Second, you need to declare your method as mutating.
Cannot assign through subscript: subscript is get-only).
Third, you are creating two new generic types that have no relation with the Dictionary generic Key and Value types.
Cannot convert value of type 'Key' (generic parameter of instance method 'add(key:value:)') to expected argument type 'Key' (generic parameter of generic struct 'Dictionary').
extension Dictionary {
mutating func add(key: Key, value: Value) {
self[key] = value
}
}
var dict: [String: Int] = [:]
dict.add(key: "One", value: 1)
dict // ["One": 1]

Related

Swift: mutate cast parameter (Error: Cannot use mutating member on immutable value of type 'MyObjectType' (aka 'Dictionary<Int, Int>')

I have a functions where I passed in Dictionary [Int : Int] as inout T and would need to write into the Dictionary. This function is included as a function of a protocol.
However, after casting T into MyObjectType (Dictionary), it becomes immutable.
Question: How can I make a generic parameter (it can be passed in as struct, class, array or dictionary) mutable after casting?
typealias MyObjectType = [Int : Int] // Key is a enum with Int as RawValue
static func myGenericFunction<T>(_ object: inout T) {
(object as! MyObjectType).updateValue(0, forKey: 1)
}
I have tried casting it to NSMutableDictionary as below which compile successfully but crash when running with simulator.
(object as! NSMutableDictionary)[Int(pMetric.selectedUnit)] = Int(pMetric.metricType)
Thanks for any good solution!

Calling Swift 4 generic method produce error

Given the following method to a Dictionary like class (Lets say the Table class) where the key and value are both data type that conforms to the protocol Value. Number types, String, Bool, and etc are extended to conform to the Value protocol.
open class Table: StoredValue {
...
open func asDictionary<K1: Value, V1: Value, K2: Value, V2: Value>(
_ kfn: (K1) -> K2 = {$0 as! K2},
_ vfn: (V1) -> V2 = {$0 as! V2}
) -> [K2: V2] where K2: Hashable {
var v = [K2: V2]()
for key in keys() {
let val = self[key]
if key is K1 && val is V1 {
v[kfn(key as! K1)] = vfn(val as! V1)
}
}
return v
}
}
The Table class itself is not a generic class but the methods for converting to native Swift container classes are generic.
The issue is calling the method from my code. I have tried to use various way to call the method, I just can't get it to work. Googling did not find any solutions either. I believe it works prior to Swift 4.x but something has change.
For example:
Calling the method with the default conversation closure as such:
let dict = options.asDictionary()
Xcode will complain (rightly so) with the error "Generic parameter 'K1' could not be inferred"
Calling the method with the target type as such:
let dict: [String: Any] = options.asDictionary()
Xcode will complain with the error "Cannot convert value of type '[_ : _]' to specified type '[String : Any]'"
Supplying the conversion closure like this:
let dict: [String: Any] = options.asDictionary({ $0 as! String }, { $0 as Any })
Xcode complains with the error "Expression type 'String' is ambiguous without more context"
Is the generic method definition wrong?

Generic dictionary extension error - ambiguous reference to subscript

I'm playing with generics in Swift 3 (Xcode 8.2.1) and I don't understand why this won't compile. I also tried self.updateValue... and that fails also.
extension Dictionary {
mutating func mergeWith<K: Hashable, V: AnyObject> (a: [K:V]) -> [K:V] {
for (k,v) in a {
self[k] = v // compile error: Ambiguous reference to member 'subscript'
}
}
}
I'm trying to limit the types of generics K and V to what works with a Dictionary, but that doesn't seem to work?
It's not a particularly helpful error, but the problem is that you're introducing new local generic placeholders K and V in your method – which need not be related in any way to the Dictionary's Key and Value types (remember that generic placeholders are satisfied by the caller, not the callee).
So just simply remove them and use the existing generic placeholders Key and Value instead, i.e take a [Key : Value] parameter. Or better still, take advantage of the fact that Swift automatically infers the generic placeholders of a generic type when you refer to it inside of itself, and just type the parameter as Dictionary (which will resolve to Dictionary<Key, Value>).
extension Dictionary {
mutating func merge(with dict: Dictionary) {
for (key, value) in dict {
self[key] = value
}
}
}
Also mutating methods usually don't return the mutated instance, so I removed the return type from your method.

How to use generics and Any.Type with functions in Swift

I'd like to keep a dictionary of keys of Enum Type and values that are managed by the Box type. But when I try to pass the key/value of each element in the dictionary to a function, I keep getting swift compiler errors on type mismatch.
I have Box declared as this:
final class Box<T> {
let value: T
init(value: T) {
self.value = value
}
}
My dictionary:
let dictionary = [Car.Nissan: Box(value: NissanHandler.Type),
Car.Honda: Box(value: HondaHandler.Type),
...]
NissanHandler and HondaHandler are both classes which inherit from a protocol named 'AutoHandler'.
As I enumerate through each key/value in the dictionary, I'd like to pass each element off to another function to process it:
Class A {
func processDictionary() {
for (key, values) in dictionary {
// This line produces the error,
// Cannot convert value of type 'Box<CarHandler.Type>' to expected argument type '[Product : Box<Any.Type>]'
processElement(key, value)
}
}
func processElement(key: Product, value: Box<Any.Type>) {
// Instantiate the class based on the value's class type
}
}
How should I declare my function so I can keep the mapping of the classes that should be instantiated at run time?
You are probably for a way to "pass" generic placeholder down to the underlying box? If so, this code might help:
func processElement<K, V>(key: K, value: V) {
}
now if I understood correctly your class would look like this:
final class Box<T> {
let value: T
init(_ value: T) {
self.value = value
}
}
class A {
let dictionary: [String: Box<Int>] = [
"a": Box(2),
"b": Box(4)
]
func processDictionary() {
dictionary.forEach(process)
}
func process<K, V>(key: K, box: Box<V>) {
print(key, box.value)
// a, 2
// b, 4
}
}
Note, that forEach(function) is a shortcut to dictionary.forEach{ k, v in function(k, v)} and is a shorter way to iterate over key, value calling a function on each of them
As for Any type, to be honest I don't remember when was the last time I used it, usually there is a better way and you always want to provide as much of type information as possible

Any? to Dictionary Cast and retrieving value

a function test receiving Any? optional object, once we are sure it's not nil, how can we get hold of underlying dictionary value.
Error: Any doesn't have a member named subscript. Casting to a Dictionary didn't help either. println(paramValue as Dictionary) Any is not convertible to Dictionary<Key, Value>
func test(params: Any?) {
if let paramValue = params {
println(paramValue)
//println(paramValue["value"])
}
}
test(["value": 10])
println(paramValue as Dictionary) won't work because dictionary is type-safe.
You could use:
println(paramValue as [String : Int])
if those will always be the right types.
If they might change, use optional casting (as? instead of as).