简体   繁体   中英

NSURLConnection is not running on the main thread

I read NSURLConnection doesn't call delegate methods , NSURLConnection didReceiveData not called and more but I am not able to find a solution to my problem. I have verified that my URL is valid and I am able to receive data with a regular nsurlconnection but not using delegate methods.

I have setup an import operation but my delegate methods are not being called. After some debugging and researching, I have realized that nsurlconnection is not running on the main thread and I believe that is why my delegate methods are not being called. I am not sure what else to try. I appreciate the help.

my import class

#import "importOperation.h"

@interface importOperation ()<NSURLConnectionDelegate>
@property (nonatomic, strong) NSURL* url;
@property (nonatomic, strong) NSURLConnection* connection;
@property (nonatomic, strong) NSMutableData* buffer;
@property (nonatomic) long long int expectedContentLength;
@property (nonatomic, readwrite) NSError* error;
@property (nonatomic) BOOL isExecuting;
@property (nonatomic) BOOL isConcurrent;
@property (nonatomic) BOOL isFinished;
@end
@implementation importOperation
-(id)initWithURL:(NSURL *)url
{
    self = [super init];
    if (self) {
        self.url = url;
    }
    return self;
}
-(void)start
{
    NSURLRequest * request = [NSURLRequest requestWithURL:self.url];
    self.isExecuting = YES;
    self.isConcurrent = YES;
    self.isFinished = NO;

    [[NSOperationQueue mainQueue]addOperationWithBlock:^{
    self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}];

}
#pragma mark NSURLConnectionDelegate
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
    return request;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    self.expectedContentLength = response.expectedContentLength;
    self.buffer = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.buffer appendData:data];
    self.progressCallback(self.buffer.length / (float)self.expectedContentLength);
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {// implemented}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    self.data = self.buffer;
    self.buffer = nil;
    self.isExecuting = NO;
    self.isFinished = YES;
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{// implemented}
- (void)setIsExecuting:(BOOL)isExecuting
{// implemented}
- (void)setIsFinished:(BOOL)isFinished
{// implemented}
- (void)cancel
{// implemented}
@end

This is how i call my import operation

-(void)getStuff:(void(^) (NSArray *result, NSError *error))completion
{

    __block importOperation *anImportOperation = nil;
    void(^completionBlock)(void)= ^(void){
        NSData * importOperationData = [anImportOperation data];
        NSError * error;
        NSDictionary * jsonDictionary = [NSJSONSerialization JSONObjectWithData:importOperationData options:NSJSONReadingMutableContainers error:&error];
        NSLog(@"parse data %@",jsonDictionary);

        completion([jsonDictionary objectForKey:@"data"],error);
    };
    anImportOperation =[[importOperation alloc]initWithURL:[ServiceManager baseURLWithResource:@"beers"]];
    [anImportOperation setCompletionBlock:completionBlock];
    [self.operationQueue addOperation:anImportOperation];

    if ([NSThread isMainThread] ==YES) {
        completionBlock();
    }
    else{
        dispatch_sync(dispatch_get_main_queue(),completionBlock);
    }

And this is the log statement

2014-12-22 23:42:58.430 Cheers[4736:621077] requested string https://api.brewerydb.com/v2/beers?key=APIKE
2014-12-22 23:42:58.456 Cheers[4736:621076] Is NOT main thread
2014-12-22 23:42:58.520 Cheers[4736:621136] PATH TO SQL STORE /Users/bla/Library/Developer/CoreSimulator/Devices/817B8B49-6316-40BD-ABF1-98C34FFD9299/data/Containers/Data/Application/252FA241-CE21-4C0E-A4DB-32D3DECC9DFB/Documents/CheersDataModel.sqlite
2014-12-22 23:42:58.647 Cheers[4736:620751] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010dc72f35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010d90bbb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010dc72e6d +[NSException raise:format:] + 205
    3   Foundation                          0x000000010d5b01bf +[NSJSONSerialization JSONObjectWithData:options:error:] + 67
    4   Cheers                          0x000000010d006396 __27-[ServiceManager getBeers:]_block_invoke + 118
    5   libdispatch.dylib                   0x00000001105107f4 _dispatch_client_callout + 8
    6   libdispatch.dylib                   0x00000001104fbec9 _dispatch_barrier_sync_f_slow_invoke + 275
    7   libdispatch.dylib                   0x00000001105107f4 _dispatch_client_callout + 8
    8   libdispatch.dylib                   0x00000001104f98fb _dispatch_main_queue_callback_4CF + 949
    9   CoreFoundation                      0x000000010dbdafe9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    10  CoreFoundation                      0x000000010db9deeb __CFRunLoopRun + 2043
    11  CoreFoundation                      0x000000010db9d486 CFRunLoopRunSpecific + 470
    12  GraphicsServices                    0x00000001121739f0 GSEventRunModal + 161
    13  UIKit                               0x000000010e2a2420 UIApplicationMain + 1282
    14  Cheers                              0x000000010d009153 main + 115
    15  libdyld.dylib                       0x0000000110545145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Your importOperationData is nil , that's why it's crashing. You need to validate the value returned from the server.

NSData * importOperationData = [anImportOperation data];
        NSError * error;

if(importOperationData)
{
   NSDictionary * jsonDictionary = [NSJSONSerialization JSONObjectWithData:importOperationData options:NSJSONReadingMutableContainers error:&error];
   if(jsonDictionary)
   {
       completion([jsonDictionary objectForKey:@"data"],error);
   }
}

You are starting your request from non-Main thread, because you are subclassing NSOperation and adding it to some self.operationQueue , which is probably not the Main Queue.

Your problem, however is, that you are invoking the completion block after adding the operation to the queue. Remove this code:

if ([NSThread isMainThread] ==YES) {
    completionBlock();
}
else{
    dispatch_sync(dispatch_get_main_queue(),completionBlock);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM