Reputation: 4493
I have an array of closures, within a class (I'm declaring this inside a UIViewController that is a table view), and want to set actions for one of my cells based on a closure. This is my code:
var actionItem : (Int)->Void = {
(index: Int)->Void in
if(self.pickedRoles[index] == "___") {
self.pickedRoles[index] = self.roles[index];
} else {
self.pickedRoles[index] = "___";
}
}
var roleActions : Array<(Int)->Void> = [{
actionItem(0);
}, {
actionItem(1);
}, {
actionItem(2);
}, {
actionItem(3);
}, {
actionItem(4);
}];
actionItem
is my closure, pickedRoles
is a class variable which is an array of Strings, similarly with roles
. I want roleActions
to represent what happens when a user selects a role, but at the line declaring roleActions
, I get an error stating:
'Int' is not a subtype of '()'
What do I do to solve this?
Upvotes: 0
Views: 229
Reputation: 535304
Well, think about it:
actionItem
is a function that takes an Int and returns Void.
actionItem(0)
is a call to that function, so it is a Void.
So {actionItem(0)}
is an anonymous function (a closure, as you call it) that takes Void and returns Void.
Well, you are trying to put that into an array of (Int)->Void
. Clearly that's a typological mismatch: an Int input is not a Void input. And that's exactly what the compiler is telling you.
Frankly I don't see what any of this has to do with closures anyway! Your goal, as you have agree in a comment, is: "I've got 5 buttons. I want the first button, when tapped, to toggle the first item in an array, the second button to toggle the second item in an array, and so on."
So what I would do is: I would simply attach tags to each button - say, 100, 101, 102, 103, 104. I would give them each the same action method. When that method is called, we subtract 100 from the tag of the sender. Now we have the index! Now we toggle the value of that index of the array.
func doButton(sender:UIView) {
let index = view.tag - 100
if(self.pickedRoles[index] == "___") {
self.pickedRoles[index] = self.roles[index];
} else {
self.pickedRoles[index] = "___";
}
}
Upvotes: 3
Reputation: 4493
As @matt and @Antonio suggested, my initial approach was faulty, but to get the desired behavior in the end, I had to go a step further than either of their solutions.
To accomplish what @matt commented, which was my goal (to have 5 buttons where each button toggles an element in the array), I had to go with the following code:
var actionItem : ((Int)->(Void->Void)) = {
(index: Int) in
return {
if(self.pickedRoles[index] == "___") {
self.pickedRoles[index] = self.roles[index];
} else {
self.pickedRoles[index] = "___";
}
};
}
var roleActions : [Void->Void] = [actionItem(0), actionItem(1), actionItem(2), actionItem(3), actionItem(4)];
What this gives me is an array of closures, where each closure can be called with no parameters to simply toggle it's respective element in the pickedRoles
array.
Upvotes: 0
Reputation: 72760
There are 2 possible ways to fix the compilation error, but I don't know which one is the correct one, depending in what you are trying to do.
The array of closures is filled in with parameterless closures:
{ Void -> Void in actionItem(0) }
So the array declaration is incorrect, the contained type should be Void -> Void
- the fixed code is:
var roleActions : Array<Void -> Void> = [{
actionItem(0);
}, {
actionItem(1);
}, {
actionItem(2);
}, {
actionItem(3);
}, {
actionItem(4);
}]
Alternatively, if the type of the element contained in the array is correct, basing on your app logic, then you just have to skip the integer parameter that's passed to each closure, using _ in
:
var roleActions : Array<Int -> Void> = [{
_ in actionItem(0);
}, {
_ in actionItem(1);
}, {
_ in actionItem(2);
}, {
_ in actionItem(3);
}, {
_ in actionItem(4);
}]
Upvotes: 1