ios - GCD serial queue with NSTimer, dispatch_sync doesn't wait for the NSTimer to complete -


i'm trying make queuehandler takes object array input executing drive commands on simple double robot. i'm trying use gcd in order serially execute functions, when i'm using dispatch_sync on queue in won't wait until nstimer has run course, continue try , execute commands next object in array.

i have 3 functions, 1 initializes nsmutablearray(loadcommands) 2 objects , runs queuehandler, called when toggle switch. queuehandler reads variables objects(type, timing, queuenr) determine type of drive function executed , how long. thought done in switch statement, , figured great if app execute function on main thread(that ok!) should wait until nstimer has run course. thought encapsulating switch case dispatch_sync solve promptly skips next iteration in loop , tries execute next function instead, drive backwards 3 seconds.

when test single object in array command executed without trouble. suppose i'm locking main thread somehow. perhaps waiting return value function in @selector in nstimer statement help?

i've played objective c 10 days, i'd appreciate bit!

- (void)loadcommands {     //create objectarray , put 2 objects inside it.      nsmutablearray *drivecommandsarray = [[nsmutablearray alloc]     initwithcapacity:4];       //command 1     drcommands *c1 = [[drcommands alloc] init];     c1.timing = 3;     c1.type = 1;     c1.queuenr = 1;     [drivecommandsarray addobject:c1];      //command 2     drcommands *c2 = [[drcommands alloc] init];     c2.timing = 3;     c2.type = 2;     c2.queuenr = 2;     [drivecommandsarray addobject:c2];      //call queuehandler     [self queuehandler:drivecommandsarray];  } 

queue handler:

- (void)queuehandler: (nsmutablearray*) commandarray {  //now, i'm not sure i'm doing here, watched tutorial      //solved vaguely similar problem , put dispatch_async before  //dispatch_sync. can't run dispatch_sync clause inside case //statement without this.      dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{      nslog(@"inside handler!");      unsigned long count;     count = [commandarray count]; //retrieve length/number of objects array.     unsigned long a;       (a = 0; < count;) {      //run loop until objects has been managed.          drcommands* myobj = (drcommands*)[commandarray objectatindex:a];          //create 2 serial queues.         dispatch_queue_t myq1;         myq1 = dispatch_queue_create("myq1", null);         dispatch_queue_t myq2;         myq2 = dispatch_queue_create("myq2", null);          int queueid = myobj.queuenr; //retrieve place in queue (not used yet)         int timeid = myobj.timing; //retrieve amount of time command shall run through nstimer         int typeid = myobj.type; //type of command          nslog(@"inside loop!");          if (queueid == a+1) {             a++;              switch (typeid) {                      {                 case 1:                     nslog(@"inside case 1");                     dispatch_sync(myq1, ^{ //doesn't wait nstimer finish,                                             //letting double drive forward 3 seconds,                                            //before resuming operations.                          counter_ = timeid;                         seconds.text = [nsstring stringwithformat:@"%d", counter_];                         timer = [nstimer scheduledtimerwithtimeinterval:1 target:self selector:@selector(jdriveforward) userinfo:nil repeats:yes];                      });                     break;                  }                     {                 case 2:                     nslog(@"inside case 2");                     dispatch_sync(myq2, ^{                          counter_ = timeid;                         seconds.text = [nsstring stringwithformat:@"%d", counter_];                         timer = [nstimer scheduledtimerwithtimeinterval:1 target:self selector:@selector(jdrivebackward) userinfo:nil repeats:yes];                     });                     break;                 }                 //add more cases                     {                 default:                     break;                 }             }         }          nslog(@"exited loop, , count %lu", a);         }     }); } 

drive commands:

//go forward x seconds. - (void)jdriveforward {     shoulddriveforward_ = yes; //sets condition recognized callback function run device forward.     counter_ -= 1;     seconds.text = [nsstring stringwithformat:@"%d", counter_];      if (counter_ <= 0) {         [timer invalidate];         shoulddriveforward_ = no;     } }  //go backwards x seconds. - (void)jdrivebackward {     shoulddrivebackward_ = yes;     counter_ -= 1;     seconds.text = [nsstring stringwithformat:@"%d", counter_];      if (counter_ <= 0) {         [timer invalidate];         shoulddrivebackward_ = no;     } } 

provided drive function experimental api i'm using

i'm using "token" such "shoulddriveforward_" inside function drivedoubleshouldupdate true duration of nstimer. must call drive methods inside function robot not default idle mode. whenever true x duration, function driving forwards or backwards active.

- (void)doubledriveshouldupdate:(drdouble *)thedouble {      float drive = (driveforwardbutton.highlighted) ? kdrdrivedirectionforward : ((drivebackwardbutton.highlighted) ? kdrdrivedirectionbackward : kdrdrivedirectionstop);     float turn = (driverightbutton.highlighted) ? 1.0 : ((driveleftbutton.highlighted) ? -1.0 : 0.0);     [thedouble drive:drive turn:turn];      //below custom functions     //the nstimer i'm using keep bool values below true x seconds,      //making robot go forward/backward through callback       //method, must use     if(shoulddriveforward_ == yes) {         [thedouble variabledrive:(float)1.0 turn:(float)0.0];     }     if(shoulddrivebackward_ == yes) {         [thedouble variabledrive:(float)-1.0 turn:(float)0.0];     }  } 

you're kind of jumbled here combination of gcd , nstimer. there's nothing can't intermixed, all-gcd approach might easier head around. think i've discerned gist of you're trying here, , hacked might helpful. i've put the whole project on github, here's meat of it:

#import "viewcontroller.h"  typedef ns_enum(nsuinteger, drcommandtype) {     drcommandunknown = 0,     drcommandtypeforward = 1,     drcommandtypebackward = 2, };  @interface drcommand : nsobject @property drcommandtype type; @property nstimeinterval duration; @end  @implementation drcommand @end  @interface viewcontroller ()  @property (weak, nonatomic) iboutlet uilabel *commandnamelabel; @property (weak, nonatomic) iboutlet uilabel *secondsremaininglabel;  @property (strong, atomic) drcommand* currentlyexecutingcommand; @property (copy, atomic) nsnumber* currentcommandstarted;  @end  @implementation viewcontroller  - (void)viewdidload {     [super viewdidload];     // initial ui update     [self updateui]; }  - (ibaction)loadcommands:(id)sender {     drcommand *c1 = [[drcommand alloc] init];     c1.duration = 3.0;     c1.type = drcommandtypeforward;      drcommand *c2 = [[drcommand alloc] init];     c2.duration = 3.0;     c2.type = drcommandtypebackward;      [self handlecommands: @[ c1, c2 ]]; }  - (void)handlecommands: (nsarray*)commands {     // safety... mutable array caller continue mutate     commands = [commands copy];      // queue our actual work     dispatch_queue_t execqueue = dispatch_queue_create(null, dispatch_queue_serial);     // we'll target main queue because simplifies updating of ui     dispatch_set_target_queue(execqueue, dispatch_get_main_queue());      // we'll use queue serve commands 1 @ time...     dispatch_queue_t latchqueue = dispatch_queue_create(null, dispatch_queue_serial);     // have target execqueue; not strictly necessary codifies relationship     dispatch_set_target_queue(latchqueue, execqueue);      // timer update our ui @ 60fps give or take, on main thread.     dispatch_source_t timer = dispatch_source_create(dispatch_source_type_timer, 0, 0, dispatch_get_main_queue());     dispatch_source_set_timer(timer, dispatch_time_now, (1.0/60.0) * nsec_per_sec, (1.0/30.0) * nsec_per_sec);     dispatch_source_set_event_handler(timer, ^{ [self updateui]; });      // suspend latch queue until we're ready go     dispatch_suspend(latchqueue);      // first thing command stream start ui updates     dispatch_async(latchqueue, ^{ dispatch_resume(timer); });      // next enqueue each command in array     (drcommand* cmd in commands)     {         dispatch_async(latchqueue, ^{             // stop queue processing other commands.             dispatch_suspend(latchqueue);              // update "machine state"             self.currentlyexecutingcommand = cmd;             self.currentcommandstarted = @([nsdate timeintervalsincereferencedate]);              // set event that'll mark end of command.             dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(cmd.duration * nsec_per_sec)), execqueue, ^{                 // clear out machine state next command                 self.currentlyexecutingcommand = nil;                 self.currentcommandstarted = nil;                  // resume latch queue next command starts                 dispatch_resume(latchqueue);             });         });     }      // after commands have finished, add cleanup block stop timer, ,     // make sure ui doesn't have stale text in it.     dispatch_async(latchqueue, ^{         dispatch_source_cancel(timer);         [self updateui];     });      // queued up, start command queue     dispatch_resume(latchqueue); }  - (void)updateui {     // make sure ever update ui on main thread.     if (![nsthread ismainthread])     {         dispatch_async(dispatch_get_main_queue(), ^{ [self updateui]; });         return;     }      drcommand* currentcmd = self.currentlyexecutingcommand;     switch (currentcmd.type)     {         case drcommandunknown:             self.commandnamelabel.text = @"none";             break;         case drcommandtypeforward:             self.commandnamelabel.text = @"forward";             break;         case drcommandtypebackward:             self.commandnamelabel.text = @"backward";             break;     }      nsnumber* starttime = self.currentcommandstarted;     if (!starttime || !currentcmd)     {         self.secondsremaininglabel.text = @"";     }     else     {         const nstimeinterval starttimedbl = starttime.doublevalue;         const nstimeinterval currenttime = [nsdate timeintervalsincereferencedate];         const nstimeinterval duration = currentcmd.duration;         const nstimeinterval remaining = max(0, starttimedbl + duration - currenttime);         self.secondsremaininglabel.text = [nsstring stringwithformat: @"%1.3g", remaining];     } }  @end 

let me know in comment if there's part you'd more explanation on.

note: other answer here has command doing sleep; approach asynchronous. approach right depend on commands actually doing wasn't clear question.


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -