Change objective C anonymous function to non anonymous one - objective-c

I'm a newbie in objective c working on swift.io and trying to convert its anonymous callbacks to non-anonymous function.
basically trying to convert
[self.Socket on:#"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
NSLog(#"socket connected");
}];
to something like
[self.Socket on:#"connect" callback:connectTestCallback];
i tried defining a following function which i'll call
- (void) connectTestCallback:(NSArray* )data withAck:(SocketAckEmitter *)ack
{
NSLog(#"socket connected");
}
But i'm not sure if thats how i'm supposed to define it, and have no idea how to call it. I've tried calling it as callback:#selector(connectTestCallback) but obviously that didn't work.
Following is definition of "on" function.
- (void)on:(NSString * __nonnull)event callback:(void (^ __nonnull)(NSArray * __nonnull, SocketAckEmitter * __nonnull))callback;

The "anonymous function" is a block building a closure. In contrast to functions and methods a closure stores its creation environment, so you can access this inside the code. But if the actual arguments are enough data to do what you want to do, you can simply send a message to self to execute the "named" method:
[self.Socket on:#"connect" callback:^(NSArray* data, SocketAckEmitter* ack)
{
[self connectTestCallback:data withAck:ack];
}];

Related

State machine to handle sequential and async events

I created this state machine to handle events. I'm unsure about my implementation firstly because I don't use a transition table or anything like that, instead, I simply input the next event/state that needs to happen. I think this is cleaner than calling method to handle event b inside the method to handle event a, right?
Secondarily, since some of the methods have parameters - and this is not swift where enum members can have associated values, I added a param for that via withObj argument. I don't see a problem with this but want to know if this is confusing/violating something from your perspective.
I also found this useful for async task, so after the task completes I set resulting value to a local variable then update state to packData using that stored value amongst many other values already existing. This value is packed in a byte array which cannot be used in blocks so this was a useful workaround - although I haven't tested yet.
States are defined via enum like so:
typedef NS_ENUM(NSUInteger, ExampleState) {
ExampleStateIdle,
ExampleStateWaitingForAsyncTask,
ExampleStateReadyToPack,
ExampleStateRespond,
ExampleStateSomethingInProgress,
ExampleStateSomething2InProgress,
ExampleStateComplete
};
Here I define a method to handle each event using helper methods. I also have an extra argument for any state that might have an associated value.
- (void)updateState:(ExampleState)state withObj:(id)obj {
self.currentState = state;
switch (state) {
case ExampleStateWaitingForAsyncTask:
[self getAsyncInfo];
break;
case ExampleStateReadyToPack:
[self packData];
break;
case ExampleStateRespond:
[self respond:obj];
break;
case ExampleStateComplete:
[self showPopup];
break;
default:
break;
}
}
Example usage:
-(void)packData {
NSData *data = [NSData dataWithBytes:&result length:resultIndex];
// next step is to respond to `client`/`central` with data
[self updateState:ExampleStateRespond withObj:data];
}

How to use "enumerateChildNodesWithName" with Swift in SpriteKit?

I'm using Swift to make a game in SpriteKit.
In Objective-C I could use the following method:
(void)enumerateChildNodesWithName:(NSString *)name usingBlock:(void (^)(SKNode *node, BOOL *stop))block
to perform actions on that *node, but I can't get this function working in Swift. Basically, I don't know how to reference that node in Swift.
This is the code I'm using, but I'm having trouble with the "usingBlock:" part. I've tried many things for many hours, but have not succeeded. Help please!
func spawnEnemy() -> () {
let enemy = SKSpriteNode(imageNamed: "enemy")
enemy.name = "enemy"
enemy.position = CGPointMake(100, 100)
self.addChild(enemy)
}
func checkCollisions() -> () {
self.enumerateChildNodesWithName("enemy", usingBlock: ((SKNode!, CMutablePointer<ObjCBool>) -> Void)?)
}
For now, don't trust autocomplete to insert the code you need — it drops in signatures from the "header", but a block signature is not the same as the declaration you need when inserting your own closure for a block parameter.
The formal way to write a closure would be to replicate the signature inside braces, adding local parameter names and using the in keyword to mark the start of the closure body:
self.enumerateChildNodesWithName("enemy", usingBlock: {
(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Void in
// do something with node or stop
})
But Swift's type inference means you don't have to write that much. Instead, you can just name the parameters, because their type (as well as the closure's return type) is known:
self.enumerateChildNodesWithName("enemy", usingBlock: {
node, stop in
// do something with node or stop
})
You can also use trailing closure syntax:
self.enumerateChildNodesWithName("enemy") {
node, stop in
// do something with node or stop
}
(You can even drop the local parameter names and refer to parameters by position — e.g. $0 for node — but here isn't a great place to do that because it makes your code far less readable. It's best to reserve $0 and friends for closures where it's blindingly obvious what the parameters are, like the closures you use with map and sort.)
See Closures in The Swift Programming Language for further explanation.
Also, because stop is an UnsafeMutablePointer, the syntax for using it is a bit different than in ObjC: set stop.memory = true to break out of enumeration.

OCMock: niceMockForClass expect zero call to method

In a test with OCMock, I must assert that no call is made to the setState: selector. However, I can make no assumption about the other calls that are made to the object.
Because any other call can be made, I have to (or do I?) use a niceMockForClass: instead of mockForClass:
How can I then make sure that no call is made to setState: ?
The code roughly looks like this:
- (void)testNoCallIsMadeToSetStateOnReset
{
self.downloader = [OCMock niceMockForClass:[Downloader class]];
[[self.downloader expectZero] setState:OCMOCK_ANY]; // <- how to do this?
// do some stuff
[self.downloader verify]
}
You can use [[yourMock reject] setState:OCMOCK_ANY];

How to enforce parameters of anonymous blocks to be unused in Objective-C?

I've run into a situation while using a library called TransitionKit (helps you write state machines) where I am want to supply entry and exit actions in the form of a callback.
Sadly, the callbacks include two completely useless parameters. A typical block has to look like this:
^void (TKState *state, TKStateMachine *stateMachine) {
// I TOTALLY don't want parameters `state` or `stateMachine` used here
};
(this is an anonymous code block. Read up on blocks here if you're unclear)
As I've noted in the comment, I really don't want those parameters even mentioned in the body there. I've tried simply removing the parameter names like suggested in this question like so:
^void (TKState *, TKStateMachine *) {
// I foobar all I like here
};
but sadly the code won't compile then :(.
How can I enforce this non-usage of parameters in code?
This is what I could come up with. Quite a hack and relies on the GCC poison pragma, which is not standard but a GNU extension - although, given that you are probably compiling this with clang anyway, it should not be a problem.
#define _state state
#define _stateMachine stateMachine
#pragma GCC poison state stateMachine
Then this compiles:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something();
}
But this doesn't:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something(state, stateMachine);
}
You could just have a function that took one kind of block, and returned another, like this:
#class TKState, TKStateMachine; // here so this will compile
typedef void (^LongStateBlock)(TKState *state, TKStateMachine *stateMachine);
static inline LongStateBlock Adapter(void(^block)()) {
void(^heapBlock)() = [block copy]; // forces block to be on heap rather than stack, a one-time expense
LongStateBlock longBlock = ^(TKState *s __unused, TKStateMachine *sm __unused) {
heapBlock();
};
// this is the non-ARC, MRR version; I'll leave ARC for the interested observer
[heapBlock release];
return [[longBlock copy] autorelease];
}
And in practice:
// this represents a library method
- (void)takesLongStateBlock:(LongStateBlock)longBlock
{
// which hopefully wouldn't look exactly like this
if (longBlock) longBlock(nil, nil);
}
- (void)yourRandomMethod
{
[self takesLongStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
NSLog(#"Gratuitous parameters, AAAAHHHH!");
}];
[self takesLongStateBlock:Adapter(^{
NSLog(#"So, so clean.");
})];
}
The whole thing is gisted, and should compile inside any class. It does what you expect when you call -yourRandomMethod.
AFAIK there is no way to do what you want when you are creating a block, you can only miss the parameter names when you are declaring a block variable(a reference to a block, to avoid misunderstandings)
So here you can miss the param names:
void (^myBlock)(SomeClass *);
But not when you create a block:
myBlock = ^(SomeClass *o)
{
};
I'd write
^void (TKState *unused_state, TKStateMachine *unused_stateMachine) {
// Anyone using unused_state or unused_stateMachine gets what they deserve.
};
Of course someone can use the parameters. But then whatever you do, they can change the code. If someone is intent on shooting themselves in the foot, there is no stopping them.

How is it better to wait an asynchronous method to be finished in iPhone app?

everybody.
I want to understand, how i shoud procceed situations when an asynchronous method has "didFinish:#selector(SEL)" parameter.
My code example is:
//
// Authentication check
- ( void )authenticationSuccess: ( GDataServiceTicket* ) ticket
authenticatedWithError: ( NSError* ) error {
if ( error == nil )
{
NSLog( #"authentication success" );
}
else
{
NSLog( #"authentication error" );
}
}
//
- ( void ) fetchFeedOfSpreadsheets {
//create and authenticate to a google spreadsheet service
if ( !(mService) )
{
GDataServiceGoogleSpreadsheet *service = [self spreadsheetService];
[mService autorelease];
mService = [service retain];
}
// check autentication success ( invoke "authenticationSuccess" method for debug success & error )
[mService authenticateWithDelegate: self
didAuthenticateSelector:#selector(authenticationSuccess:
authenticatedWithError:) ];
// HERE I WANT TO MAKE A PAUSE AND WHAIT THE RESULT, EITHER I AUTHENTICATED OR NOT
// AND MAKE AN "IF" STATEMENT TO CONTINTUE WORKING ON SERVER, OR RETURN ERROR
//fetch retrieves the feed of spreadsheets entries
NSURL *feedURL = [ NSURL URLWithString: kGDataGoogleSpreadsheetsPrivateFullFeed ];
GDataServiceTicket *ticket;
ticket = [mService fetchFeedWithURL: feedURL
delegate: self
didFinishSelector: #selector(spreadsheetsTicket:finishedWithFeed:
error: ) ];
// HERE I WANT TO WAIT SECOND TIME. I WANT "spreadsheetsTicket:
// finishedWithFeed:error:" TO PROCCEED ERROR AND PUT A FEED IN SOME NSARRAY OBJECT
// AND AFTER THAT I WANT TO WORK WITH THAT NSARRAY RIGHT HERE
}
I's clear, that i can push the code i want into the end of "authenticationSuccess" method section, but it's also clear, that it's a wrong a way to solve the proble. There a number of situations like this, where i call an asynchronous method with a selector parameter, and i want to find a solution providing me a flexible code writing.
Thanks in advance.
It's a standard practice in Objective-C to put the code to be executed after the authentication in the authenticationSucess: method. You might not like it, but that is life.
Many people had the same complaint as you, so
on iOS 4 and later, there's something called blocks which allow you to write the code to be executed after the authentication in the method which initiates the authentication, as in
[mService authenticateAndExecute:^{
code to be executed when successfully authenticated ;
} whenError:^{
code to be executed when authentication failed;
} ];
But in this case you need to modify the API, which is possible by using categories. See this blog post by Mike Ash. He has many other posts on blocks on the same blog, which are also very instructive.
If you're going to use a library that works asynchronously (and therefore doesn't block your UI), you should have a good reason for trying to force it to work synchronously.
You should be checking for an authentication error at the end of your authenticationSuccess:authenticatedWithError: method, and calling the next request from there if there's a success. Similarly, in your spreadsheetsTicket:finishedWithFeed:error: check for an error, and continuing processing if there isn't one. It might be a better design to do that continued work in a separate method, but that's up to you.
Is there a specific reason you want to use the GData API in a synchronous fashion?