gpt4 book ai didi

objective-c - 在 Objective-C 中同步异步任务

转载 作者:搜寻专家 更新时间:2023-10-30 20:05:18 24 4
gpt4 key购买 nike

我正在尝试使用 GCDAsyncSocket 将一些图像文件(将近 100MB)发送到我的 iDevice 客户端。

我想同步向客户端发送数据包。我的意思是在将 100MB 的数据发送到第一个客户端后迭代到下一个客户端。但是由于 GCDAsyncSocket 的异步性质,我不知道如何序列化这些数据包发送。

我不能使用信号量,因为在发送图像之前,我与每个客户协商以了解我应该发送哪些图像,然后尝试发送这些图像。而且我找不到一种巧妙的方式来等待并向信号量发出信号。

- (void)sendImagesToTheClients:clients
{
...
//negotiating with client to know which images should sent
...

for(Client* client in clients)
{
packet = [packet addImages: images];
[self sendPacket:packet toClient:client];
}
}

- (void)sendPacket:packet toClient:client
{
// Initialize Buffer
NSMutableData *buffer = [[NSMutableData alloc] init];
NSData *bufferData = [NSKeyedArchiver archivedDataWithRootObject:packet];

uint64_t headerLength = [bufferData length];
[buffer appendBytes:&headerLength length:sizeof(uint64_t)];
[buffer appendBytes:[bufferData bytes] length:[bufferData length]];

// Write Buffer
[client.socket writeData:buffer withTimeout:-1.0 tag:0];
}

这是 AsyncSocket 写入数据的工作原理:

- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
{
if ([data length] == 0) return;

GCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];

dispatch_async(socketQueue, ^{ @autoreleasepool {

LogTrace();

if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))
{
[writeQueue addObject:packet];
[self maybeDequeueWrite];
}
}});

// Do not rely on the block being run in order to release the packet,
// as the queue might get released without the block completing.
}

那么如何同步这个任务呢?

更新

对于套接字连接,我使用 GCDAsyncSocket它大量使用委托(delegate)来进行事件通知。(GCDAsyncSocket.h 和 GCDAsyncSocket.m)(没有带有 completionHandler 的方法)。

我编写了一个名为 TCPClient 的类,它处理套接字连接和数据包发送,并将其设置为初始化套接字的委托(delegate)。写入数据包后,委托(delegate)方法 - (void)soc​​ket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag 被调用。这只告诉我一些数据已经写入。这里我不能根据写入的数据来决定调用dispatch_group_leave。所以依赖委托(delegate)方法是没有用的。

我修改了 GCDAsyncSocket.h 和 .m 文件中的 [client.socket writeData:buffer withTimeout:-1.0 tag:0] 来接受一个 completionBlock: [client.socket writeData:buffer withTimeout:-1.0 tag: 0 完成 block :完成 block ]使用这种方法可以帮助我解决同步异步任务。

// perform your async task
dispatch_async(self.socketQueue, ^{
[self sendPacket:packet toClient:client withCompletion:^(BOOL finished, NSError *error)
{
if (finished) {
NSLog(@"images file sending finished");
//leave the group when you're done
dispatch_group_leave(group);
}
else if (!finished && error)
{
NSLog(@"images file sending FAILED");
}
}];

但问题是在更新 GCDAsyncsocket 之后,我的代码可能会崩溃。在这里,我正在寻找将完成处理程序添加到 GCDAsyncsocket 而无需直接修改它的简洁方法。比如围绕它创建一个包装器或使用 objective-c 运行时的特性。你有什么想法吗?

最佳答案

您可以使用调度组来完成此操作。对于带有完成 block 的异步任务:

//create & enter the group
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);

// perform your async task
dispatch_async(socketQueue, ^{

//leave the group when you're done
dispatch_group_leave(group);
});

// wait for the group to complete
// (you can use DISPATCH_TIME_FOREVER to wait forever)
long status = dispatch_group_wait(group,
dispatch_time(DISPATCH_TIME_NOW,NSEC_PER_SEC * COMMAND_TIMEOUT));

// check to see if it timed out, or completed
if (status != 0) {
// timed out
}

或者对于有委托(delegate)的任务:

@property (nonatomic) dispatch_group_t group;

-(BOOL)doWorkSynchronously {

self.group = dispatch_group_create();
dispatch_group_enter(self.group);

[object doAsyncWorkWithDelegate:self];

long status = dispatch_group_wait(self.group,
dispatch_time(DISPATCH_TIME_NOW,NSEC_PER_SEC * COMMAND_TIMEOUT));

// A
if (status != 0) {
// timed out
return NO
}

return YES;
}

-(void)asyncWorkCompleted {}

// after this call, control should jump back to point A in the doWorkSynchronously method
dispatch_group_leave(self.group);
}

关于objective-c - 在 Objective-C 中同步异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26617212/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com