Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/121.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用GCDAsyncSocket的同步通信_Ios_Objective C_Grand Central Dispatch_Cocoaasyncsocket_Gcdasyncsocket - Fatal编程技术网

Ios 使用GCDAsyncSocket的同步通信

Ios 使用GCDAsyncSocket的同步通信,ios,objective-c,grand-central-dispatch,cocoaasyncsocket,gcdasyncsocket,Ios,Objective C,Grand Central Dispatch,Cocoaasyncsocket,Gcdasyncsocket,我正在应用程序中使用GCDAsyncSocket(CocoaAsyncSocket)进行套接字通信。由于GCDAsyncSocket的异步特性,我的网络请求(submitMessage)与接收数据时运行的回调块分离(socket:didReadData) 这种方法适用于一次性交易。但在某些情况下,我需要发布一个请求,然后使用收到的数据发布另一个请求。我不能让它正常工作。基本上,我需要这样的东西: [self submitMessage:request1 onCompletion:^(NSDict

我正在应用程序中使用
GCDAsyncSocket
CocoaAsyncSocket
)进行套接字通信。由于
GCDAsyncSocket
的异步特性,我的网络请求(
submitMessage
)与接收数据时运行的回调块分离(
socket:didReadData

这种方法适用于一次性交易。但在某些情况下,我需要发布一个请求,然后使用收到的数据发布另一个请求。我不能让它正常工作。基本上,我需要这样的东西:

[self submitMessage:request1 onCompletion:^(NSDictionary *response1) {
    (...callback 1...)
    }];
    [self submitMessage:request2 onCompletion:^(NSDictionary *response2) {
        (...callback 2...)
    }];
}];

其中订单严格为request1-callback1-request2-callback2

所以问题是,如何阻止在第一个请求回调后运行的第二个请求?
GCD
dispatch\u sync
?)会是一条路吗

编辑


我最终使用了一种类似于@tigloo建议的解决方案(因此接受了他的答案),但使用了
NSCondition
而不是
GCD
(如果有人对细节感兴趣,我会遵循)。我已经在运行多个线程(UI在主线程中,高级套接字通信在另一个线程中,套接字操作在第三个线程中)。设置类属性并使用
NSCondition
锁定
GCDAsyncSocket
委托直到响应到达似乎是最干净的方法。

最简单的方法是将请求附加到串行调度队列,然后使用dispatch_sync()等待它们完成

实现它的实际方式取决于您的偏好。一个可能的想法如下:

  • 创建一个新类“SyncRequest”
  • 理想情况下,此类具有bool“requestFinished”类型的私有属性,在类的init方法中初始化为NO
  • 在“sendSyncRequest”等方法中,您调用submitMessage:completionBlock:
  • 完成块将“requestFinished”属性设置为YES
  • “sendSyncRequest”中的最后一行是dispatch_sync(syncRequestQueue,^(void){while(!requestFinished);})
通过这种方式,您可以构造SyncRequest的多个实例,每个实例处理一个同步请求。草图实施:

@interface SyncRequest
@property bool requestFinished;
@end

@implementation SyncRequest

dispatch_queue_t syncRequestQueue;    

-(id)init
{
   self = [super init];
   if ( !self )
      return nil;

   self.requestFinished = NO;
   syncRequestQueue = dispatch_queue_create("com.yourid.syncrequest", DISPATCH_QUEUE_SERIAL);

   return self;
}

-(void) sendSyncRequest:(NSDictionary*)messageObject
{
   // submit message here and set requestFinished = YES in completion block

   // wait for completion here
   dispatch_sync(syncRequestQueue, ^(void){while(!self.requestFinished);});
}

@end

注意:我在编写代码时手头没有编译器,为了避免循环引用,您可能必须在dispatch\u sync调用中创建对“self”的间接引用。

我想您差不多做到了。那怎么办

[self submitMessage:request1 onCompletion:^(NSDictionary *response1) {
    // here, do something with response1 and create request2...
    // then you can make request2 directly at the end of the callback:
    [self submitMessage:request2 onCompletion:^(NSDictionary *response2) {
        // here, do something with response2...
    }];
}];

不需要GCD指令,也不需要阻止执行(这是一种糟糕的做法)。这能解决您的问题吗?

请说得更清楚些,不要太冗长。你到底有什么问题。(我读过你的帖子,但很难找出问题所在。)谢谢@ilmiacs,现在请看看它是否更有意义。那么你为什么不在完成后在callback1中提交
消息:request2
?谢谢,我已经读过你发布的帖子了;我原则上知道GCD应该如何工作,只是不知道在这种特殊情况下如何使用它。如果我在串行队列上发送请求,我如何等待回调执行?请求将立即返回,因为它是异步的(GCDAsyncSocket的工作方式)。我已经添加了一个示例来说明我的意思。只要主块(request1)没有立即完成,这将很好地工作。是的,第一个回调块将最终运行,是的,第二个请求及其(第二个)回调也将最终运行。但是我需要启动一组这样的组(request1-request2),如果它们不按顺序运行,套接字将变得混乱,因为回调中的写入将混合,读取将获得错误的数据。有道理吗?呃。。。我认为你的实施应该保证不会出现这样的问题。让人困惑的不是插座。这是你的协议实现。所以第一:回调在您确实收到数据时被调用,因此在我的实现中,request2将在收到响应后被调用,这回答了您最初的问题。第二:您的评论表明,在一个request1已经运行时调用另一个request1将不起作用。(我同意。)阻止对套接字的写入将是一种方法,尽管我不推荐这种方法。最好修改协议,这样它就不会混淆。那么你有什么建议吗?基本上,我有一个“同步”方法,由一系列发送/接收/发送/接收交换组成;我需要以同步的方式触发一系列的“同步”。我不知道如何改进我的协议,这是最基本的。套接字编程绝非小事。改进并不是变得更基本。改进就是健壮性。首先,我建议你回顾一下这个看似基本的协议是否有意义。考虑所有可能发生的情况。网络中断、超时、部分消息丢失、重复传递数据等。如果您对所有这些情况都有计划,并且您仍然认为同步是正确的路径,考虑它是否真的值得麻烦,或者选择一个更高级别的协议来处理所有那些有一个实现的问题。如果你仍然坚持,那么就做一个Realest1-CalbRe1-Reavest2-CalbRe2序列的协议的一个操作。然后将操作排队,确保在最后一个操作完成后立即开始下一个操作。这将解决您在评论中提出的问题。如果不提供进一步的细节,我无法猜测下一个问题会出现。祝你好运
@interface SyncRequest
@property bool requestFinished;
@end

@implementation SyncRequest

dispatch_queue_t syncRequestQueue;    

-(id)init
{
   self = [super init];
   if ( !self )
      return nil;

   self.requestFinished = NO;
   syncRequestQueue = dispatch_queue_create("com.yourid.syncrequest", DISPATCH_QUEUE_SERIAL);

   return self;
}

-(void) sendSyncRequest:(NSDictionary*)messageObject
{
   // submit message here and set requestFinished = YES in completion block

   // wait for completion here
   dispatch_sync(syncRequestQueue, ^(void){while(!self.requestFinished);});
}

@end
[self submitMessage:request1 onCompletion:^(NSDictionary *response1) {
    // here, do something with response1 and create request2...
    // then you can make request2 directly at the end of the callback:
    [self submitMessage:request2 onCompletion:^(NSDictionary *response2) {
        // here, do something with response2...
    }];
}];