objective c - Can't retain block retrieved from within another block -


i trying write unit test method creates , passes block object (so can called later). method using socket.io-objc send request server. passes callback block socketio's sendevent:withdata:andacknowledge invoked when receives response server). here method want test:

typedef void(^myresponsecallback)(nsdictionary * response); 

...

-(void) sendcommand:(nsdictionary*)dict withcallback:(myresponsecallback)callback andtimeoutafter:(nstimeinterval)delay {     __block bool didtimeout = false;     void (^timeoutblock)() = nil;      // create block invoke if request times out     if (delay > 0)     {         timeoutblock = ^         {             // set flag if response can suppress             didtimeout = true;              // invoke original callback no response argument (to indicate timeout)             callback(nil);         };     }      // create callback/ack invoked when response     socketiocallback cb = ^(id argsdata)     {         // if callback invoked after ui timed out, ignore response. otherwise, invoke         // original callback         if (!didtimeout)         {             if (timeoutblock != nil)             {                 // cancel timeout timer                 [nsobject cancelpreviousperformrequestswithtarget:self selector:@selector(onrequesttimeout:) object:timeoutblock];             }              // invoke original callback             nsdictionary * responsedict = argsdata;             callback(responsedict);         }     };      // send event server     [_socketio sendevent:@"message" withdata:dict andacknowledge:cb];      if (timeoutblock != nil)     {         // if timeout value specified, set timeout         [self performselector:@selector(onrequesttimeout:) withobject:timeoutblock afterdelay:delay];     } }  -(void) onrequesttimeout:(id)arg {     if (nil != arg)     {         // arg block, execute         void (^callback)() = (void (^)())arg;         callback();     } } 

this appears working fine when running real. problem comes in when run unit test (which uses sentestingkit , ocmock):

-(void)testsendrequestwithnotimeout {     nsdictionary * cmd = [[nsdictionary alloc] initwithobjectsandkeys:                           @"thecommand", @"msg", nil];     __block bool callbackinvoked = false;     __block socketiocallback socketiocallback = nil;     myresponsecallback requestcallback = ^(nsdictionary * response)     {         stassertnotnil(response, @"response dictionary invalid");         callbackinvoked = true;     };      // expect controller emit message     [[[_mocksocket expect] anddo:^(nsinvocation * invocation) {         socketiocallback temp;         [invocation getargument:&temp atindex:4];          // isn't working i'd expect         socketiocallback = [temp copy];          stassertnotnil(socketiocallback, @"no callback passed socket.io sendevent method");     }] sendevent:@"message" withdata:cmd andacknowledge:ocmock_any];      // send command dio     [_iocontroller sendcommand:cmd withcallback:requestcallback];      // make sure callback not invoked yet     stassertfalse(callbackinvoked, @"response callback invoked before receiving response");      // fake response coming     socketiocallback([[nsdictionary alloc] initwithobjectsandkeys:@"msg", @"response", nil]);      // make sure original callback invoked result     stasserttrue(callbackinvoked, @"original requester did not callback when msg recvd"); } 

to simulate response, need capture (and retain) block created method i'm testing , passed sendevent. passing 'anddo' argument expectation, able access block i'm looking for. however, seems not being retained. so, when sendevent unwinds , go invoke callback, values should have been captured in block show null. result test crashes when invoke socketiocallback , goes access 'callback' value captured part of block (and nil).

i using arc , expect "__block socketiocallback socketiocallback" retain values. i've tried "-copy" block variable still not seem retain past end of sendcommand. can force block retain long enough me simulate response?

note: i've tried calling [invocation retainarguments] works crashes somewhere in objc_release when cleaning after test complete.

i able reproduce problem , suspect error in code section:

socketiocallback temp; [invocation getargument:&temp atindex:4]; 

extracting block way not work correctly. i'm not sure why may have of magic arc in background. if change code following should work you'd expect:

void *pointer; [invocation getargument:&pointer atindex:4]; socketiocallback temp = (__brigde socketiocallback)pointer; 

Comments

Popular posts from this blog

linux - Does gcc have any options to add version info in ELF binary file? -

javascript - Clean way to programmatically use CSS transitions from JS? -

android - send complex objects as post php java -