How to get server response data in NSURLSession without completion block

前端 未结 1 376
醉酒成梦
醉酒成梦 2020-12-02 08:38

I am using NSURLSession for background image uploading. And according to uploaded image my server gives me response and I do change in my app accordingly. But I

相关标签:
1条回答
  • 2020-12-02 09:04

    A couple of thoughts:

    First, instantiate your session with a delegate, because background sessions must have a delegate:

    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kSessionIdentifier];
    self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    

    Second, instantiate your NSURLSessionUploadTask without a completion handler, because tasks added to a background session cannot use completion blocks. Also note, I'm using a file URL rather than a NSData:

    NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromFile:fileURL];
    [task resume];
    

    Third, implement the relevant delegate methods. At a minimum, that might look like:

    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
        NSMutableData *responseData = self.responsesData[@(dataTask.taskIdentifier)];
        if (!responseData) {
            responseData = [NSMutableData dataWithData:data];
            self.responsesData[@(dataTask.taskIdentifier)] = responseData;
        } else {
            [responseData appendData:data];
        }
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
        if (error) {
            NSLog(@"%@ failed: %@", task.originalRequest.URL, error);
        }
    
        NSMutableData *responseData = self.responsesData[@(task.taskIdentifier)];
    
        if (responseData) {
            // my response is JSON; I don't know what yours is, though this handles both
    
            NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
            if (response) {
                NSLog(@"response = %@", response);
            } else {
                NSLog(@"responseData = %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
            }
    
            [self.responsesData removeObjectForKey:@(task.taskIdentifier)];
        } else {
            NSLog(@"responseData is nil");
        }
    }
    

    Note, the above is taking advantage of a previously instantiated NSMutableDictionary called responsesData (because, much to my chagrin, these "task" delegate methods are done at the "session" level).

    Finally, you want to make sure to define a property to store the completionHandler provided by handleEventsForBackgroundURLSession:

    @property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void);
    

    And obviously, have your app delegate respond to handleEventsForBackgroundURLSession, saving the completionHandler, which will be used below in the URLSessionDidFinishEventsForBackgroundURLSession method.

    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
        // This instantiates the `NSURLSession` and saves the completionHandler. 
        // I happen to be doing this in my session manager, but you can do this any
        // way you want.
    
        [SessionManager sharedManager].backgroundSessionCompletionHandler = completionHandler;
    }
    

    And then make sure your NSURLSessionDelegate calls this handler on the main thread when the background session is done:

    - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
        if (self.backgroundSessionCompletionHandler) {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.backgroundSessionCompletionHandler();
                self.backgroundSessionCompletionHandler = nil;
            });
        }
    }
    

    This is only called if some of the uploads finished in the background.

    There are a few moving parts, as you can see, but that's basically what's entailed.

    0 讨论(0)
提交回复
热议问题