gpt4 book ai didi

ios - 一次异步地从多个 pffile 下载数据

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:06:10 25 4
gpt4 key购买 nike

如果我有一个 Message 对象数组,每个对象都有一个包含数据的 PFile ,是否可以通过像这样异步排队来下载每条消息的数据所以:

for (int i = 0; i < _downloadedMessages.count; i++) {
PFObject *tempMessage = (PFObject *)[_downloadedMessages objectAtIndex:i];
[[tempMessage objectForKey:@"audio"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
[self persistNewMessageWithData:data];
}];
}

这似乎导致我的应用程序挂起,即使这应该在后台完成...

使用下面的解决方案:

NSMutableArray* Objects = ...

[self forEachPFFileInArray:Objects retrieveDataWithCompletion:^BOOL(NSData* data, NSError*error){
if (data) {
PFObject *tempObj = (PFObject *)Object[someIndex...];
[self persistNewMessageWithData:data andOtherInformationFromObject:tempObj];
return YES;
}
else {
NSLog(@"Error: %@", error);
return NO; // stop iteration, optionally continue anyway
}
} completion:^(id result){
NSLog(@"Loop finished with result: %@", result);
}];

最佳答案

您可能遇到的是,对于同时运行的大量异步请求,系统可能会由于内存压力和网络停顿或其他资源访问耗尽而阻塞(包括中央处理器)。

您可以使用带有“分配”工具的 Instruments 来验证内存压力的发生。

在内部(即在 Parse 库和系统中)可能有一个变量集,它设置可以同时运行的最大网络请求数。尽管如此,在您的 for 循环中,您将所有请求排入队列。

根据您的情况排队请求意味着什么,此过程根本不是免费的。它可能会消耗大量内存。在最坏的情况下,网络请求将被系统排队,但底层网络堆栈仅执行最大数量并发请求。其他入队待定请求卡在那里等待执行,而它们的网络超时已经在运行。这可能会导致取消未决事件,因为它们的超时已过。

最简单的解决方案

好吧,解决上述问题的最明显方法是简单地序列化所有任务。也就是说,它仅在前一个异步任务完成后才启动下一个异步任务(包括完成处理程序中的代码)。可以使用我命名为“异步循环”的异步模式来完成此操作:

“异步循环”是异步的,因此有一个完成处理程序,它会在所有迭代完成时被调用。

typedef void (^loop_completion_handler_t)(id result);
typedef BOOL (^task_completion_t)(PFObject* object, NSData* data, NSError* error);

- (void) forEachObjectInArray:(NSMutableArray*) array
retrieveDataWithCompletion:(task_completion_t)taskCompletionHandler
completion:(loop_completion_handler_t)completionHandler
{
// first, check termination condition:
if ([array count] == 0) {
if (completionHandler) {
completionHandler(@"Finished");
}
return;
}
// handle current item:
PFObject* object = array[0];
[array removeObjectAtIndex:0];
PFFile* file = [object objectForKey:@"audio"];
if (file==nil) {
if (taskCompletionHandler) {
NSDictionary* userInfo = @{NSLocalizedFailureReasonErrorKey: @"file object is nil"}
NSError* error = [[NSError alloc] initWithDomain:@"RetrieveObject"
code:-1
userInfo:userInfo];
if (taskCompletionHandler(object, nil, error)) {
// dispatch asynchronously, thus invoking itself is not a recursion
dispatch_async(dispatch_get_global(0,0), ^{
[self forEachObjectInArray:array
retrieveDataWithCompletion:taskCompletionHandler
completionHandler:completionHandler];
});
}
else {
if (completionHandler) {
completionHandler(@"Interuppted");
}
}
}
}
else {
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
BOOL doContinue = YES;
if (taskCompletionHandler) {
doContinue = taskCompletionHandler(object, data, error);
}
if (doContinue) {
// invoke itself (note this is not a recursion")
[self forEachObjectInArray:array
retrieveDataWithCompletion:taskCompletionHandler
completionHandler:completionHandler];
}
else {
if (completionHandler) {
completionHandler(@"Interuppted");
}
}
}];
}
}

用法:

// Create a mutable array 
NSMutableArray* objects = [_downloadedMessages mutableCopy];

[self forEachObjectInArray:objects
retrieveDataWithCompletion:^BOOL(PFObject* object, NSData* data, NSError* error){
if (error == nil) {
[self persistNewMessageWithData:data andOtherInformationFromObject:object];
return YES;
}
else {
NSLog(@"Error %@\nfor PFObject %@ with data: %@", error, object, data);
return NO; // stop iteration, optionally continue anyway
}
} completion:^(id result){
NSLog(@"Loop finished with result: %@", result);
}];

关于ios - 一次异步地从多个 pffile 下载数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22265390/

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