Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift array of handler blocks

In objective-c I have a code in .h file:

typedef void(^SocketConnectionLost)();
typedef void(^SocketIOCallback)(id argsData);

@interface SocketConnection

@property (strong, nonatomic) SocketIO *socketIO;

@property (strong, nonatomic) NSMutableArray *socketConnectionLosts;

-(void)sendEventWithName:(NSString*)eventName
                withData:(id)data
        onConnectionLost:(SocketConnectionLost)connectionLost
                onAnswer:(SocketIOCallback)answer;

@end

And I have a code in .m file:

@implementation SocketConnection

- (void)init {
    self.socketIO = [[SocketIO alloc] initWithDelegate:self];
    [self.socketIO setReturnAllDataFromAck: YES];
    [self.socketIO connectToHost:kSocketHost onPort:kSocketPort withParams:params];
}

- (void) socketIODidDisconnect:(SocketIO *)socket
         disconnectedWithError:(NSError *)error {
    for(ServerRequestConnectionLost connectionLost in self.socketConnectionLosts)
        if(connectionLost)
            connectionLost();
    [self.socketConnectionLosts removeAllObjects];
}

-(void)sendEventWithName:(NSString*)eventName
                withData:(id)data
        onConnectionLost:(SocketConnectionLost)connectionLost
                onAnswer:(SocketIOCallback)answer {
    [self.socketConnectionLosts addObject:connectionLost];
    [self.socketIO sendEvent:eventName withData:data andAcknowledge:^(id argsData) {
        if(connectionLost)
            [self.socketConnectionLosts removeObject:connectionLost];
        if(answer)
            answer(argsData);
    }];
}

@end

Please help me reproduce this code in Swift, I don't understand how to create, add and remove Swift blocks with Array on NSArray

This is how I try to create some block in Swift:

var someBlock: ()->()
var connectionLosts = NSMutableArray()
connectionLosts.append(someBlock)

Compiler show me the error: Type '()->()' doesn't confirm to protocol 'AnyObject'

Then I need to remove someBlock from the array, like [self.socketConnectionLosts removeObject:connectionLost] in obj-c and I don't understand how to do it with Swift array.

like image 635
imike Avatar asked Dec 04 '22 05:12

imike


1 Answers

You don't have to use an objective-c array, just a swift array. Check this out:

typealias ClosureType = () -> ()

var someClosure: ClosureType = { println("Closure executed") }

var array = [ClosureType]()

array.append(someClosure)

array[0]()

If you run that in playground, the last line will print Closure executed.

The reason why a NSArray doesn't work is that it is bridged as an array of AnyObject in swift - but AnyObject is an instance of any class type, and obviously a closure is not a class.

As for removing an item from an array, that's a more complicated issue. find cannot be used because it requires the array type to implement the Equatable protocol, but closures don't implement it, and they cannot be extended.

Maybe rather than using an array you can use a dictionary, with a key type that makes sense for you depending on your app logic - such as a textual name, an enum, etc. For example, if you use an enum:

enum ClosureEnum {
    case TEST_ELEMENT
}

var dict = [ClosureEnum:ClosureType]()
dict[.TEST_ELEMENT] = someClosure
dict[.TEST_ELEMENT]!()

Note the ! in dict[.TEST_ELEMENT]!(), required because a lookup in a dictionary always return an optional. You can use forced unwrapping like that, or enclose it in an optional binding for safer code.

To remove an element, just use the proper method:

dict.removeValueForKey(.TEST_ELEMENT)
like image 109
Antonio Avatar answered Feb 03 '23 07:02

Antonio