How can I call a function with a dictionary?

How can I call a function with a dictionary?



I try to create a Dictionary to call some functions.


Dictionary



My array takes a key Int, a String and a function, like this:


let list_weapons: [Int: [Any]] = [1: ["Sword", attack_sword],
2: ["Magic wand", heal_magic_wand],
3: ["Hammer", attack_hammer],
4: ["Axe", attack_axe]]



These functions take a Class as a parameter, like this:


Class


func attack_sword(character: Character)



I try to call my function like that but it doesn't work.


list_weapons[1]![1](character: Character)



Cannot call value of non-function type 'Any'



If you have some ideas or advise me with another container



Thank you




4 Answers
4



Using an array of Any to store a string and a closure (function) with a specific signature is a poor choice. It would be better to declare a struct with two properties of the correct type. Then store those structures in your dictionary.


Any


struct


struct Action
let name: String
let function: (Character) -> ()


let list_weapons: [Int: Action] = [
1: Action(name: "Sword", function: attack_sword),
// and the rest
]

list_weapons[1]!.function(someCharacter)



You don't need to store methods in a dictionary to solve your problem. In my opinion, an architecture solution would be better here. You can play with selectors if you like, but I guess things will be much easier if you just do something like that


// Here you can specify all common thing about your weapons
protocol Weapon: class
var name: String get
func attack(character: Character)


// Each weapon has its own class which can contain eveything you need
class Sword: Weapon
class MagicWand: Weapon
class Hammer: Weapon
class Axe: Weapon

// That's how you can store you weapons list
// You can use a dictionary if you like
let weaponsArray: [Weapon] = [Sword(),
MagicWand(),
Hammer(),
Axe()]

// And that's how you can use them
weaponsArray[0].attack(character: character)






"You can't store methods in the array." - sure you can.

– rmaddy
Sep 18 '18 at 17:40






@rmaddy Answer updated, thanks!

– Yury Imashev
Sep 18 '18 at 17:57




You have to cast Any to the Function before using it.


cast


let f = (list_weapons[1]![1] as! (Character) -> Void)
f("a") //it will invoke attack_sword("a")



And without temp variable,


(list_weapons[1]![1] as! (Character) -> Void)("a")



You can cast the element to a function type:


if let attack = list_weapons[1]![1] as? ((Character) -> Void)
attack(...)
else
print("Cannot attack")



But you better rework your data model. Using dictionaries can get confusing very quickly. Here's one way to do it:


protocol Weapon
var name: String get
func attack(character: Character)


struct Sword: Weapon
let name = "Sword"
func attack(character: Character) ...


struct MagicWand: Weapon
let name = "Magic Wand"
func attack(character: Character) ...


struct Hammer: Weapon
let name = "Hammer"
func attack(character: Character) ...


struct Axe: Weapon
let name = "Axe"
func attack(character: Character) ...


let weapons: [Weapon] = [Sword(), MagicWand(), Hammer(), Axe()]
weapons[1].attack(character: ...)



You extend each weapon with different damages, unique features, levels, etc.



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)