ios – objective-c中的循环和异步连接

ios – objective-c中的循环和异步连接,第1张

概述我有一个表名称数组,希望循环遍历它们并获取它们的名称并附加一个URL来创建与Web服务的连接以下载 JSON数据.循环似乎首先工作,数组中的三个表名中的每一个都被用于创建与Web服务的连接并且数据被下载但是当循环结束时(从3变为0)循环出现再次启动并为数组中的最后两个表无限循环. 记录输出(注意扬声器和参展商反复重复): 2013-12-16 10:38:08.755 WebServiceTest @H_502_0@ @H_502_0@ 我有一个表名称数组,希望循环遍历它们并获取它们的名称并附加一个URL来创建与Web服务的连接以下载 JSON数据.循环似乎首先工作,数组中的三个表名中的每一个都被用于创建与Web服务的连接并且数据被下载但是当循环结束时(从3变为0)循环出现再次启动并为数组中的最后两个表无限循环.

记录输出(注意扬声器和参展商反复重复):

2013-12-16 10:38:08.755 WebServiceTest[501:60b] loopCount = 32013-12-16 10:38:08.758 WebServiceTest[501:60b] table name = workshop2013-12-16 10:38:08.817 WebServiceTest[501:60b] LoopCount is: 2 2013-12-16 10:38:08.821 WebServiceTest[501:60b] loopCount = 22013-12-16 10:38:08.822 WebServiceTest[501:60b] table name = exhibitor2013-12-16 10:38:08.827 WebServiceTest[501:60b] LoopCount is: 12013-12-16 10:38:08.830 WebServiceTest[501:60b] loopCount = 12013-12-16 10:38:08.831 WebServiceTest[501:60b] table name = speaker2013-12-16 10:38:08.835 WebServiceTest[501:60b] LoopCount is: 02013-12-16 10:38:09.199 WebServiceTest[501:3707] Status code = 2002013-12-16 10:38:09.204 WebServiceTest[501:3707] Objects in current table - speaker = 12013-12-16 10:38:09.207 WebServiceTest[501:3707] Status code = 2002013-12-16 10:38:09.210 WebServiceTest[501:3707] Objects in current table - exhibitor = 22013-12-16 10:38:09.229 WebServiceTest[501:450b] Status code = 2002013-12-16 10:38:09.234 WebServiceTest[501:450b] Objects in current table - speaker = 12013-12-16 10:38:09.240 WebServiceTest[501:3707] Status code = 2002013-12-16 10:38:09.244 WebServiceTest[501:3707] Objects in current table - exhibitor = 22013-12-16 10:38:09.271 WebServiceTest[501:450b] Status code = 2002013-12-16 10:38:09.274 WebServiceTest[501:450b] Objects in current table - speaker = 12013-12-16 10:38:09.294 WebServiceTest[501:450b] Status code = 2002013-12-16 10:38:09.298 WebServiceTest[501:4803] Status code = 2002013-12-16 10:38:09.302 WebServiceTest[501:4803] Objects in current table - exhibitor = 22013-12-16 10:38:09.309 WebServiceTest[501:4803] Status code = 2002013-12-16 10:38:09.337 WebServiceTest[501:4803] Objects in current table - speaker = 12013-12-16 10:38:09.338 WebServiceTest[501:4803] Status code = 2002013-12-16 10:38:09.341 WebServiceTest[501:4803] Objects in current table - exhibitor = 22013-12-16 10:38:09.347 WebServiceTest[501:4803] Status code = 2002013-12-16 10:38:09.352 WebServiceTest[501:4803] Objects in current table - speaker = 12013-12-16 10:38:09.311 WebServiceTest[501:450b] Objects in current table - workshop = 143

vIEwController.h:

#import <UIKit/UIKit.h>@interface VIEwController : UIVIEwController<UItableVIEwDataSource,UItableVIEwDelegate,NSURLConnectionDataDelegate>{NSMutableArray *arraytable;}@property (weak,nonatomic) IBOutlet UItableVIEw *mytableVIEw;@property NSMutableArray *tables;@property NSMutableArray *tablenames;@property NSMutableURLRequest *request;@property Nsstring *tablename;-(voID) startUpdate;typedef voID(^completion_t)(NSArray* objects,NSError*error);-(voID)fetchData:(Nsstring *)tablename   withCompletion:(completion_t)completionHandler;-(voID)fetchObjectsWithtablename:(Nsstring*)tablename                  completion:(completion_t)completionHandler;

vIEwController.m:

#import "VIEwController.h"@implementation VIEwController- (voID)vIEwDIDLoad{    [self startUpdate];    [super vIEwDIDLoad];    [[self mytableVIEw]setDelegate:self];    [[self mytableVIEw]setDataSource:self];    arraytable =[[NSMutableArray alloc]init];}-(voID)startUpdate{    NSArray* tablenames =  @[@"speaker",@"exhibitor",@"workshop"];     NSUInteger loopCount = tablenames.count;    while (loopCount > 0){        Nsstring *tablename = [tablenames objectAtIndex:loopCount -1];        NSLog(@"loopCount = %lu",(unsigned long)loopCount);        NSLog(@"table name = %@",tablename);        [self fetchObjectsWithtablename:[tablename mutablecopy] completion:^(NSArray* objects,NSError*error){            if (error) {                NSLog(@"Error: %@",error);            } else {                NSLog(@"Result: %@",objects);            }        }];        loopCount --;        NSLog(@"LoopCount is: %i",loopCount);    }}-(voID)fetchObjectsWithtablename:(Nsstring*)tablename                  completion:(completion_t)completionHandler;{    [self fetchData:tablename withCompletion:^(NSArray* objects,NSError*error){        if (objects) {            [self.tables addobject:objects];            [self fetchObjectsWithtablename:tablename completion:completionHandler];        }        else if (objects == nil){            NSLog(@"objects = %@",objects);            NSLog(@"break out of FOWTN");        } else {            NSLog(@"Objects is something else...");        }    }];    if (completionHandler) {        completionHandler(self.tables,nil);    }}-(voID)fetchData:(Nsstring *)tablename                    withCompletion:(completion_t)completionHandler{    Nsstring *currentURL = [Nsstring stringWithFormat:@"https://testAPI.someURL.com/API/congress/%@",tablename];    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:currentURL]];    [request addValue:@"application/Json" forhttpheaderFIEld:(@"Accept")];    [NSURLConnection sendAsynchronousRequest:request                                       queue:[[NSOperationQueue alloc] init]                           completionHandler:^(NSURLResponse *response,NSData *data,NSError *error)     {         NSError* err = error;         NSArray* objects; // final result array as a representation of JsON Array         if (response) {             NShttpURLResponse *newResp = (NShttpURLResponse*)response;             if (newResp.statusCode == 200) {                 NSLog(@"Status code = %li",(long)newResp.statusCode);                 if ([data length] >0 && error == nil)                 {                     NSError* localError;                     objects = [NSJsONSerialization JsONObjectWithData:data options:kNilOptions error:&error];                     if (objects) {                         if (completionHandler) {                             completionHandler(objects,nil);                         }                         //NSLog(@"Objects in current table - %@ = %@",tablename,objects);                         NSLog(@"Objects in current table - %@ = %lu",(unsigned long)objects.count);                             return;                     } else {                         err = localError;                     }                 } else {                    // err = ...                 }             }         }         if (objects == nil) {             NSLog(@"nothing found in table: %@",tablename);             //assert(err);             if (completionHandler) {                 completionHandler(nil,err);             }         }    }];}
解决方法 (编辑:已删除)

恕我直言,循环看起来更好用for循环,在“右”方向迭代:

-(voID)startUpdate{    NSUInteger count = tablenames.count;    for (int i = 0; i < count; ++i){        Nsstring *tablename = [tablenames objectAtIndex:i];        ...    }}

一些额外的建议:

说完这个并修复了这个问题,现在,你需要意识到你正在循环块中调用异步方法.因此你的startUpdate方法也变得异步!

如果您希望在完成所有异步方法后通知调用站点,则startUpdate可以使用完成处理程序:

- (voID) startUpdateWithCompletion:(completion_t)completionHandler;

您可以在for循环中调用异步方法.但实际上,这将并行处理所有异步任务,除非底层异步任务通过在“大小”(并发 *** 作数)可配置的专用共享队列上执行来自行处理.

现在,一个合适的具体实现取决于您的要求,即您是否需要控制同时运行的任务的数量以及您希望在何处完成此任务.它还取决于您是否希望能够在任何时候从任何其他线程取消循环,如果这是必要的话.

例如:

假设,我们不对底层异步任务做任何假设,这意味着它们不会使用共享专用队列来限制同时运行的任务本身的数量.此外,您希望确保所有任务一个接一个地运行 – 或串行运行.

一种方法(几种方法)是使用NSOperationQueue,将其最大 *** 作数设置为1,并添加需要包装到“并发”NSOperation中的异步任务.

“并发”NSOperation是一个需要以start方法启动的 *** 作,该方法是异步的.基本上,当您的异步任务完成时, *** 作将完成.当添加到NSOperationQueue时,队列会在何时开始 *** 作.

不幸的是,将NSOperation子类化为并发 *** 作需要注意一些细微之处.官方文档Subclassing Notes没有详细描述它们,因此您可以在此处查看此代码段:Canonical Implementation of a Subclass of NSOperation.

现在,假设你有一个正确的NSOperation子类,称之为FetchtableOperation:

completion_t completionHandler = ^(..) {..};NSOperationQueue* queue = [[NSOperationQueue alloc] init];queue.maxConcurrentoperations = 1;for (Nsstring tablename in self.tablenames) {    FetchtableOperation* op =        [[FetchtableOperation alloc] initWithname:tablename                                      completion: ^{...}];    [queue addOperation:op];}

为了在 *** 作完成时得到通知,添加“sentinel”块:

[queue addOperationWithBlock:^{     // finished}];

警告:

>您需要创建并发NSOperation的正确子类来包装异步方法.
>上次 *** 作完成时会收到通知,而不是上次 *** 作完成块完成时的通知!
>完成处理程序仍然可以并行执行! (除非它们在主线程或大小等于1的专用队列上执行)
>除非任务数量非常大,否则所有任务都将排队 – 这不是问题.每个排队的任务都会消耗一点系统RAM.

使用NSOperationQueue的优点是您可以随时取消挂起的 *** 作.此外,您可以使用属性maxConcurrentoperations轻松调整队列的大小,即最大并发 *** 作的数量.

其他方法:

使用dispatch_group同时运行所有任务

相比之下,这是一种快速简便的解决方案.但是,您的任务将并行启动:

dispatch_group group = dispatch_group_create();for (Nsstring* tablename in self.tablenames) {    dispatch_group_enter(group);    [self fetchObjectsWithtablename:tablename completion:^{        ...        dispatch_group_leave(group);    }];}dispatch_group_notify(group,dispatch_get_main_queue(),^{    ... // all tasks *and* all completion handler finished});

“异步循环”按顺序运行异步任务:

这也是一个非常简单的解决方案 – 一旦你理解了模式.

How to download multiple images asynchronously in iOS without effect on UI?

使用顺序调用异步任务的NSArray类:

这是一个“可重用”组件,一旦实现,就可以轻松使用.您可以按如下方式使用它:

typedef voID (^unary_async_t)(ID input,completion_t completion);typedef voID (^completion_t)(ID result);unary_async_t task = ^(ID input,completion_t completionHandler){    [self fetchObjectsWithtablename:input completion:^(NSData* result,NSError*error){         if (error == nil) {             ... ;         }         completionHandler(error ? error : @"OK");    }];  };NSArray* tablenames =  @[@"speaker",@"workshop"]; [tablenames forEachApplyTask:task completion:^(ID result){    // result is an array containing the result of each operation in the same order    ...}];

https://gist.github.com/couchdeveloper/6155227

@H_502_0@ 总结

以上是内存溢出为你收集整理的ios – objective-c中的循环和异步连接全部内容,希望文章能够帮你解决ios – objective-c中的循环和异步连接所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1006213.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存