Objective c NSO操作之间的数据传输

Objective c NSO操作之间的数据传输,objective-c,json,nsoperation,nsoperationqueue,Objective C,Json,Nsoperation,Nsoperationqueue,我希望获得以下信息:我在NSOperationQueue中有两个NSOperations。第一个是从网站下载(获取一些json数据),第二个是解析这些数据。这是相关的操作。 我不明白如何把它们联系起来。如果它们都已分配且在队列中,如何将json字符串传输到解析它的操作?如果此队列位于另一个NSOperationQueue内,该NSOperationQueue执行由前面提到的两个NSOperation组成的NSOperation,是否有问题 我所能找到的只是将数据传输到主线程上的委托(perfor

我希望获得以下信息:我在NSOperationQueue中有两个NSOperations。第一个是从网站下载(获取一些json数据),第二个是解析这些数据。这是相关的操作。 我不明白如何把它们联系起来。如果它们都已分配且在队列中,如何将json字符串传输到解析它的操作?如果此队列位于另一个NSOperationQueue内,该NSOperationQueue执行由前面提到的两个NSOperation组成的NSOperation,是否有问题

我所能找到的只是将数据传输到主线程上的委托(performSelectorOnMainThread),但我需要在后台执行所有这些操作

谢谢。 代码: NSDownload:NSOperation

    - (instancetype)initWithURLString:(NSString *)urlString andDelegate:(id<JSONDataDelegate>)delegate
{
    self = [super init];
    if (self) {
        _urlStr = urlString;
        _delegate = delegate; /// this needs to be a NSOPeration
        _receivedData = [NSMutableData dataWithCapacity:256];
    }
    return self;
}

#pragma mark - OVERRIDE

    - (void)main
    {
        @autoreleasepool {

            if (self.isCancelled) {
                return;
            }

            NSURL *url = [NSURL URLWithString:self.urlStr];
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            self.urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
        }
    }

    #pragma mark - NSURLConnectionDataDelegate

    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        if (self.isCancelled) {
            [connection cancel];
            self.receivedData = nil;
            return;
        }
        [self.receivedData appendData:data];
    }

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        if (self.isCancelled) {
            self.receivedData = nil;
            return;
        }
        // return data to the delegate
        NSDictionary *responseDict = @{JSON_REQUESTED_URL : self.urlStr,
                                       JSON_RECEIVED_RESPONSE : self.receivedData};
        [(NSObject *)self.delegate performSelectorOnMainThread:@selector(didReceiveJSONResponse:) withObject:responseDict waitUntilDone:NO]; // ok to uses performSelector as this data is not for use on the main thread ???
    }

    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        // return error to the delegate
        [(NSObject *)self.delegate performSelectorOnMainThread:@selector(didFailToReceiveDataWithError:) withObject:error waitUntilDone:NO];
    }
-(instancetype)initWithURLString:(NSString*)urlString和delegate:(id)delegate
{
self=[super init];
如果(自我){
_urlStr=urlString;
_delegate=delegate;///这需要是一个NSO操作
_receivedData=[NSMutableData数据,容量:256];
}
回归自我;
}
#pragma标记-覆盖
-(无效)主要
{
@自动释放池{
如果(自我取消){
返回;
}
NSURL*url=[NSURL-URLWithString:self.urlStr];
NSURLRequest*request=[nsurlRequestRequestWithURL:url];
self.urlConnection=[[NSURLConnection alloc]initWithRequest:request delegate:self startimely:YES];
}
}
#pragma标记-NSURLConnectionDataDelegate
-(void)连接:(NSURLConnection*)连接didReceiveData:(NSData*)数据
{
如果(自我取消){
[连接取消];
self.receivedData=nil;
返回;
}
[self.receiveddataappenddata:data];
}
-(无效)连接IDFinishLoading:(NSURLConnection*)连接
{
如果(自我取消){
self.receivedData=nil;
返回;
}
//将数据返回给代理
NSDictionary*responseDict=@{JSON_REQUESTED_URL:self.urlStr,
JSON_收到_响应:self.receivedData};
[(NSObject*)self.delegate performSelector OnMainThread:@selector(didReceiveJSONResponse:)with Object:ResponseDecit waitUntilDone:NO];//确定使用performSelector,因为此数据不用于主线程???
}
-(无效)连接:(NSURLConnection*)连接失败错误:(NSError*)错误
{
//将错误返回给委托
[(NSObject*)self.delegate performSelectorOnMainThread:@selector(didFailToReceiveDataWithError:)with object:error waitUntilDone:NO];
}

正如lucianomarisi所指出的,通常最好让第一个操作生成第二个操作。这通常更易于管理。在我的经验中,操作依赖性并不是很常见

也就是说,当然可以在操作之间传递数据。例如,您可以在第二个操作中创建
数据源
属性。这将是要求提供其数据的目的;该对象将是第一个操作。不过,这种方法可能需要锁定

您还可以在第一个操作中创建
nextOp
属性。完成后,它将在退出之前在第二个操作上调用
setData:
。您可能不需要为此锁定,但您可能需要。在大多数情况下,第一次手术最好是在此时安排下一次手术(这看起来也像卢西亚诺马里西的答案)

关键是操作只是一个对象。它可以有您想要的任何方法和属性。您可以将一个操作传递给另一个操作

请记住,由于操作在后台运行,因此没有理由需要使用异步接口来
NSURLConnection
。同步API(
sendSynchronousRequest:returningResponse:error:
对此很好,编码也简单得多。您甚至可以使用一个简单的
NSBlockOperation
。或者,您可以使用异步
NSURLConnection
接口,但实际上不需要
NSOperation

我还注意到:

    _receivedData = [NSMutableData dataWithCapacity:256];
真的是这么一小段JSON数据吗?很难相信将这么小的解析操作转移到后台值得这么复杂


(顺便说一句,除非您确切知道内存的大小,否则手动指定容量通常没有多大好处。即使如此,也不总是清楚它是否有好处。我相信
NSURLConnection
现在正在使用隐藏的调度数据,所以您实际上是在请求一个永远不会使用的内存块。当然se Cocoa也不会分配它,因为它优化了这一点……关键是,您可以只使用
[NSMutableData]
。Cocoa在这类事情上非常聪明;您通常只能阻碍它的优化。)

正如Rob所说,除非您有任何特定的理由使用操作,否则请使用同步调用。然后在主线程或任何其他需要的线程上执行选择器。除非您希望在单独的操作或线程(显式)中分离检索和解析

以下是我用于json检索和解析的代码:

-(BOOL) loadWithURL:(NSString*) url params: (NSDictionary*) params andOutElements:(NSDictionary*) jElements
{

}@user1028028:

使用以下方法

1) 维护用于添加DownloadOperation的操作队列引用

2) 在ConnectionIDFinishLoading方法中,创建ParseOperation实例,设置json数据并将其添加到操作队列中。在DownloadOperation中维护ParseOperation强引用变量,并通过DownloadOperation接口处理解析操作的取消

3) 完成解析后,在主线程中调用UI功能


我希望这有帮助。

您真的需要同时创建这两个
N
NSError *reqError = nil;
NSString* urlStr = @"";//@"http://";
urlStr = [urlStr stringByAppendingString:url];

NSURL* nsURL = [NSURL URLWithString:urlStr];

//Private API to bypass certificate ERROR Use only for DEBUG
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[nsURL host]];


NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: nsURL
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:60.0];

[request setHTTPMethod:@"POST"];
NSString *postString = @"";
if(params!=nil) {
    NSEnumerator* enumerator = params.keyEnumerator;
    NSString* aKey = nil;
    while ( (aKey = [enumerator nextObject]) != nil) {
        NSString* value = [params objectForKey:aKey];

        //Use our own encoded implementation instead of above Apple one due to failing to encode '&'
        NSString* escapedUrlString =[value stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
        //Required to Fix Apple bug with not encoding the '&' to %26
        escapedUrlString =  [escapedUrlString stringByReplacingOccurrencesOfString: @"&" withString:@"%26"];

        //this is custom append method. Please implement it for you -> the result should be 'key=value' or '&keyNotFirst=value'
        postString = [self appendCGIPairs:postString key:aKey value:escapedUrlString isFirst:false];
    }
}


//************** Use custom enconding instead !!!! Error !!!!! **************
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];


NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&reqError];
if(reqError!=nil) {
    NSLog(@"SP Error %@", reqError);
    return NO;
}

NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
//Handles Server Errors during execution of the web service that handles the call.
if([json_string hasPrefix:@"ERROR"] == YES){
    NSLog(@"SP Error %@", lastError);
    return NO;
}

//Very Careful!!!!!! Will stop for any reason.!!!!!!
//Handles errors from IIS Server that serves teh request.
NSRange range = [json_string rangeOfString:@"Runtime Error"];
if(range.location != NSNotFound) {
    NSLog(@"SP Error %@", lastError);
    return NO;
}

//Do the parsing
jElements = [[parser objectWithString:json_string error:nil] copy];
if([parser error] == nil) {
    NSLog(@"Parsing completed");
} else {
    jElements = nil;
    NSLog(@"Json Parser error: %@", parser.error);
    NSLog(@"Json string: %@", json_string);
    return NO;
}

//Parsed JSON will be on jElements
return YES;