Search code examples
objective-cios9xcode7nsurlsessionafnetworking-3

AFNetworking 1.x to 3.x migration for NSURLSessionTask?


I have a old project which is not working in iOS 9. I've read official documentation on AFNetworking and completed most of the migration.

NetworkManager:

_requestManager = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:baseURL ]];
//here we can set the request header as the access token once we have logged in.
AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
[_requestManager setRequestSerializer:requestSerializer];
[_requestManager setResponseSerializer:responseSerializer];

Earlier Version:

// 2. Create an `NSMutableURLRequest`.
NSMutableURLRequest *request =
    [[NetworkManager sharedInstance].requestManager.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:fullPath
                                                                                          parameters:nil
                                                                           constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
    NSString *fileName = [NSString stringWithFormat:@"%@.caf", theAudioItem.media_item_name];
    [formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:@"audio/caf"];
}];

// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
AFHTTPRequestOperation *operation =
    [[NetworkManager sharedInstance].requestManager HTTPRequestOperationWithRequest:request
                                                                            success: ^(AFHTTPRequestOperation *operation, id responseObject) {
    result(YES, @"");
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
    if (operation.responseData) {
        NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableContainers error:nil];

        result(NO, [responseDict valueForKey:@"Message"]);
        [self deleteTmpFilesFromParts:formParts];
    } else {
        result(NO, [NSString stringWithFormat:@"Failed to upload media to %@!", gallery.gallery_name]);
        [self deleteTmpFilesFromParts:formParts];
    }


    result(NO, errorMessage);
}];

// 4. Set the progress block of the operation.
[operation setUploadProgressBlock: ^(NSUInteger __unused bytesWritten,
                                     long long totalBytesWritten,
                                     long long totalBytesExpectedToWrite) {
    DLog(@"progress is %i %lld %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
    progress((float)totalBytesWritten / (float)totalBytesExpectedToWrite);
}];

// 5. Begin!
[operation start];

Converted Response: ( updated with comments what gives errors )

//No visible @interface for 'AFHTTPRequestSerializer<AFURLRequestSerialization>' declares the selector 'multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:'
    NSMutableURLRequest *request =
        [[NetworkManager sharedInstance].requestManager.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:fullPath parameters:nil
                                                                               constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
        NSString *fileName = [NSString stringWithFormat:@"%@.caf", theAudioItem.media_item_name];
        [formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:@"audio/caf"];
    }];

    // 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
   //No visible @interface for 'AFHTTPSessionManager' declares the selector 'HTTPRequestOperationWithRequest:success:failure:'
    NSURLSessionTask *operation =
        [[NetworkManager sharedInstance].requestManager HTTPRequestOperationWithRequest:request
                                                                                success: ^(NSURLSessionTask *operation, id responseObject) {
        result(YES, @"");
    } failure: ^(NSURLSessionTask *operation, NSError *error) {

        //Error for operation doesn't have responseData
        if (operation.responseData) {
            NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableContainers error:nil];

            result(NO, [responseDict valueForKey:@"Message"]);
            [self deleteTmpFilesFromParts:formParts];
        } else {
            result(NO, [NSString stringWithFormat:@"Failed to upload media to %@!", gallery.gallery_name]);
            [self deleteTmpFilesFromParts:formParts];
        }

        // get the response
        result(NO, errorMessage);
    }];

    // 4. Set the progress block of the operation.
    //No visible @interface for 'NSURLSessionTask' declares the selector 'setUploadProgressBlock:'
    [operation setUploadProgressBlock: ^(NSUInteger __unused bytesWritten,
                                         long long totalBytesWritten,
                                         long long totalBytesExpectedToWrite) {
        DLog(@"progress is %i %lld %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
        progress((float)totalBytesWritten / (float)totalBytesExpectedToWrite);
    }];

    // 5. Begin!
    //No visible @interface for 'NSURLSessionTask' declares the selector 'start'
    [operation start];

Solution

  • The equivalent code for AFHTTPSessionManager is simply:

    NSURLSessionTask *task = [[[NetworkManager sharedInstance] requestManager] POST:fullPath parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSString *fileName = [NSString stringWithFormat:@"%@.caf", theAudioItem.media_item_name];
        [formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:@"audio/caf"];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"%.3f", uploadProgress.fractionCompleted);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // success
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // failure
    
        // if you need to process the `NSData` associated with this error (if any), you'd do:
    
        NSData *data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
        if (data) { ... }
    }];
    

    This features two major changes from your v1.x code: First, with 2.x they introduced GET/POST/etc. methods that saved you from manually starting the operation (or adding it to your own queue). Second, with 3.x, they retired NSOperation framework of AFHTTPRequestOperationManager, and now use AFHTTPSessionManager class, where GET/POST/etc. don't return an NSOperation subclass, but rather a NSURLSessionTask reference.