ios - Send command and wait for reply - Wait for delegate in Obj-C -
my goal achieve synchronized communication custom device i.e. next command can send when reply received. i'm doing in way
device class implements devicedelegate protocol
//device.h @class device; @protocol devicedelegate <nsobject> - (void)didrecivereplywithdata:(nsdata *)data; @end @interface device : nsobject {}
in deviceviewcontroller implementation:
@interface deviceviewcontroller() { bool waitingforreply = false; } @end @implementation deviceviewcontroller - (void)sendcommandwithdata:(nsdata *)data { if ( waitingforreply == false) { //send command code waitingforreply = true; } } - (void)didrecivereplywithdata:(nsdata *)data { //code waitingforreply = false; } @end
but wish in more elegant way i.e. using gcd (semaphores?) blocks (completionhandler?). ideas?
ps. sorry, forgot mention: commands sended device while
waitingforreply = true
should ignored!!!.
possibly best approach here create queue of commands nsoperationqueue
.
since, presumably, communication device asynchronous have subclass nsoperation
encapsulate communication.
@interface devicecommandoperation : nsoperation <devicedelegate> @property (nonatomic, assign) bool waitingforreply; @property (nonatomic, copy) nsdata *datatosend; @property (nonatomic, copy) nsdata *datareceived; @end @implementation devicecommandoperation - (instancetype)initwithdata:(nsdata *)datatosend { self = [super init]; if (self) { _datatosend = [datatosend copy]; } return self; } - (void)setwaitingforreply:(bool)waitingforreply { if (_waitingforreply != waitingforreply) { [self willchangevalueforkey:@"isexecuting"]; [self willchangevalueforkey:@"isfinished"]; _waitingforreply = waitingforreply; [self didchangevalueforkey:@"isexecuting"]; [self didchangevalueforkey:@"isfinished"]; } } - (void)start { self.waitingforreply = yes; // simulate sending command , waiting response. // need replace actual communication mechanism. dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(0.5 * nsec_per_sec)), dispatch_get_main_queue(), ^{ // in reality call presumably come device [self didreceivereplywithdata:somedata]; }); } - (void)didreceivereplywithdata:(nsdata *)data { self.datareceived = data; self.waitingforreply = no; } #pragma mark - nsoperation - (bool)isasynchronous { return yes; } - (bool)isexecuting { return _waitingforreply; } - (bool)isfinished { return !_waitingforreply; } @end
this operation could used deviceviewcontroller
(it better architecturally have responsibility elsewhere that's not topic of question).
@interface deviceviewcontroller () @property (nonatomic, strong) nsoperationqueue *operationqueue; @end @implementation deviceviewcontroller - (nsoperationqueue *)operationqueue { if (_operationqueue == nil) { _operationqueue = [[nsoperationqueue alloc] init]; } return _operationqueue; } - (void)sendnextcommand { nsdata *data = // data next command [self sendcommandwithdata:data]; } - (void)sendcommandwithdata:(nsdata *)data { nslog(@"queueing operation"); devicecommandoperation *operation = [[devicecommandoperation alloc] initwithdata:data]; // operation's completionblock gets called on background queue [operation setcompletionblock:^{ nslog(@"devicecommandoperation completed"); // process operation.datareceived [self sendnextcommand]; }]; [self.operationqueue addoperation:operation]; } @end
this approach allow determine (if any) command send next, based on reply previous command.
if know of "commands" want send , don't need finer grained control create instances of devicecommandoperation
each command, set queue's maxconcurrentoperationcount
1, , add each devicecommandoperation
queue (in order want them processed).
Comments
Post a Comment