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)
@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
"You can't store methods in the array." - sure you can.
– rmaddy
Sep 18 '18 at 17:40