Objective C: Posting Foundation Objects with AFNetworking

The scenario was this. I had Objective C objects which I needed to parse as JSON, and send a POST request to a web server. At first, I used RestKit because that’s the framework that’s being used in the project, but that was giving issues, so I decided to strip it down a level, and use AFNetworking. I searched the internet for hours on how to do it, and good reading was hard to find. Here’s how I did it to anyone who may be in this position in future:

First of all, the here’s a simplified version of the piece of code that does the work. I’ll talk through it step by step:

NSMutableURLRequest *request = [self postRequestWithObject:objectToParse andPath:@"path/to/endpoint"]; 
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];   
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
    // What happens when it goes right }   
failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
    // What happens when it goes wrong 
}]; 
[requestOperation start];

The first line calls a method which creates the request object based on the path to the endpoint. This method is as follows:

- (NSMutableURLRequest *)postRequestWithObject:(NSObject *)object andPath:(NSString *)path 
{ 
    NSString *baseUrl = @"www.codingafro.co/"; 
    NSString *fullUrlString = [NSString stringWithFormat:@"%@%@", baseUrl, path]; 
    NSURL *requestURL = [NSURL URLWithString:fullUrlString]; 
    NSMutableURLRequest *request = [[NSURLRequest requestWithURL:requestURL] mutableCopy]; 
    request.HTTPMethod = @"POST"; 
    [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
    [request addValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
    NSError *error = nil; 
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[object dictionaryOfProperties] options:NSJSONWritingPrettyPrinted error:&error]; 
    NSMutableData *bodyData = [NSMutableData data]; 
    [bodyData appendData:jsonData]; 
    request.HTTPBody = bodyData; 
    return request; 
}

The complete URL is first built up based on the base url, as well as the path to the endpoint. After this a request object is created based on the URL to the endpoint. A dictionary of property names and values of the object is then created, and this is serialised into JSON. This JSON is added to the body of the request.

To create a dictionary of property names and values, I created a category of NSObject so that it can be used by other objects at other times. This may not be the best approach, and I’m open to correction:

#import <objc/runtime.h> 

@implementation NSObject (Utility) 

- (NSDictionary *)dictionaryOfProperties 
{ 
    NSMutableDictionary *objectPropertyValueDictionary = [[NSMutableDictionary alloc] init]; 
    unsigned int numberOfProperties = 0; 
    objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties); 

    for (NSUInteger i = 0; i < numberOfProperties; i++) 
    { 
        objc_property_t property = propertyArray[i];  
        NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)]; 
        NSString *value = [self valueForKey:name]; 
        [objectPropertyValueDictionary addEntriesFromDictionary:@{ name : value }]; 
    } 

    return objectPropertyValueDictionary; 
} 

@end

Back to the original code excerpt, now that we have the request, we just create a request operation (AFHTTPRequestOperation), and set the completion and failure blocks. Then start the operation. And done.

Any way that this can be improved?

Patrick Kayongo

I create and maintain software. Pan-African.

Johannesburg, South Africa