我需要为JSON Web服务创建多个NSURLConnections。我希望每个WS调用都保持在UI中,可能带有UIActivityIndicatorView和标签。到目前为止,我已经创建了一个NSURLConnection帮助程序类来处理连接并将URL委托放在View中。这适用于使用单个WS调用更新UI。
对于多个来电,我正在尝试使用NSOperationQueue。我想将setMaxConcurrentOperationCount设置为队列中的一个,以便每个Operation一次执行一个。这是我的View Controller上的相关代码:
ViewController.m
#import "URLOperationHelper.h"
@implementation ViewController
- (IBAction)showPopup:(id)sender
{
// Dictonary holds POST values
NSMutableDictionary *reqDic = [NSMutableDictionary dictionary];
// Populate POST key/value pairs
[reqDic setObject:@"pw" forKey:@"Password"];
[reqDic setObject:@"ur" forKey:@"UserName"];
operationQueue = [[NSOperationQueue alloc] init];
[operationQueue setMaxConcurrentOperationCount:1];
[operationQueue cancelAllOperations];
[operationQueue setSuspended:YES];
URLOperationHelper *wsCall1 = [[URLOperationHelper alloc] initWithURL:@"urlString1" postParameters:reqDic urlDelegate:self];
URLOperationHelper *wsCall2 = [[URLOperationHelper alloc] initWithURL:@"urlString2" postParameters:reqDic urlDelegate:self];
[operationQueue addOperation:wsCall1];
[operationQueue addOperation:wsCall2];
}
// Did the URL Connection receive a response
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"Did receive response: %@", response);
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode];
// Handle status code here
webData = [[NSMutableData alloc]init];
}
// Did the URL Connection receive data
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"Did receive data: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
assert(webData != nil);
[webData appendData:data];
}
// Did the connection fail with an error?
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%@", error);
}
// Executes after a successful connection and data download
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"Connection finished");
}
@end
这是我的 URLOperationHelper.m
@implementation URLHelper
- (id)initWithURL:(NSString *)urlPath
postParameters:(NSMutableDictionary *)postParameters
urlParentDelegate:(id) pDelegate
{
if(self = [super init])
{
connectionURL = urlPath;
postParams = postParameters;
parentDelegate = pDelegate;
}
return self;
}
- (void)done
{
// Cancel the connection if present
if(urlConnection)
{
[urlConnection cancel];
urlConnection = nil;
}
// Alert
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
executing = NO;
finished = YES;
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
}
- (void)cancel
{
// Possibly add an NSError Property
[self done];
}
- (void)start
{
// Make sure this operation starts on the main thread
if(![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
// Make sure that the operation executes
if(finished || [self isCancelled])
{
[self done];
return;
}
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
[self main];
[self willChangeValueForKey:@"isExecuting"];
}
- (void)main
{
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postParams options:NSJSONWritingPrettyPrinted error:&error];
// Convert dictionary to JSON
NSString *requestJSON = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"JSONRequest: %@", requestJSON);
// Declare Webservice URL, request, and return data
url = [[NSURL alloc] initWithString:connectionURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [NSData dataWithBytes:[requestJSON UTF8String] length:[requestJSON length]];
// Build the request
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:requestData];
// Connect to Webservice
// Responses are handled in the delegates below
urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:parentDelegate startImmediately:YES];
}
- (BOOL)isConcurrent
{
return YES;
}
- (BOOL)isExecuting
{
return executing;
}
-(BOOL)isFinished
{
return finished;
}
@end
我遇到的问题是从不调用URLOperation的Start方法。创建OperationQueue并调用操作,但在此之后,执行或线程方式都没有发生。
此外,使用像这样的NSOperationQueues提供UI反馈是否正确? I.E.从Operation?
调用NSURLDelegates答案 0 :(得分:3)
如果在添加操作之前将setSuspended
设置为YES
,那么您的操作将排队到暂停的队列中。我建议不要暂停队列
此外,您的操作无论如何都不会结束。您需要将操作本身指定为委托并实现所有必需的委托方法。在这些方法中,您可以将邮件转发到parentDelegate
并确定完成时间并在适当时调用您的完成方法(我建议connection:didFailWithError:
和connectionDidFinishLoading:
)
这里有一个很好的教程:http://blog.9mmedia.com/?p=549
您也没有完全实现正确的键值编码兼容属性。每当您致电willChangeValueForKey:
时,您还需要事后致电didChangeValueForKey
:
- (void)start
{
...
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
[self didChangeValueForKey:@"isExecuting"];
[self main];
}
和
- (void)done
{
...
// Alert
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
executing = NO;
finished = YES;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
}
请参阅此Q / A for KVC:when to use "willChangeValueForKey" and "didChangeValueForKey"?