Reputation: 191
I try to create a Dictionary
to call some functions.
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:
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
Upvotes: 2
Views: 76
Reputation: 2128
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)
Upvotes: 2
Reputation: 93161
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.
Upvotes: 0
Reputation: 318814
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.
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)
Upvotes: 0
Reputation: 21728
You have to cast
Any to the Function before using it.
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")
Upvotes: 0