Online Book Reader

Home Category

iOS Recipes - Matt Drance [68]

By Root 221 0
*)type

nameParam:(NSString *)nameParam

filename:(NSString *)fileName;

Finally, there’s a method to prepare the HTTP body for upload. It takes two blocks: one for successful completion and the other for any error that occurred while constructing the body. We’ll explain why these blocks are necessary (as opposed to a simple return value) shortly.

MultipartHTTPPost/PRPMultipartPOSTRequest.h

- (void)prepareForUploadWithCompletionBlock:(PRPBodyCompletionBlock)completion

errorBlock:(PRPBodyErrorBlock)error;

The complete flow for using PRPMultipartPOSTRequest is as follows:

Create a request object.

Set a custom boundary.

Set basic form parameters (if needed).

Add an upload file.

Prepare the request for submission.

The file and parameter steps are interchangeable. As we saw in the earlier example, any basic form data is presented as "Content-Disposition: form-data;" with the parameter name, followed by two line breaks and the value. The binary data for the file attachment is similarly structured in the body but also includes a content type and the aforementioned filename.

So, we have all the pieces we need; now we just have to glue it all together. This is where ‑prepareForUploadWithCompletionBlock:errorBlock: comes in: it takes any previously set parameters and the upload file and prepares a full multipart body from them.

We start by identifying the HTTP body as a multipart POST. We also set a temporary filename for the body content itself. Since this body is more complicated, and potentially much larger, than our basic POST, saving the body to a file makes it easier to recover from errors, interruptions, or app termination. It also prevents us from potentially running out of memory by managing all of this data in memory.


Managing Temporary Files

This recipe saves the body to the temp directory with a randomized filename. The system cleans out the temp directory automatically at unspecified intervals, so if you want to manage the files yourself, save them to caches, documents, or some other directory in your app’s sandbox. Remember, though, that you will then be responsible for deleting the body file when it’s no longer neeeded.

MultipartHTTPPost/PRPMultipartPOSTRequest.m

- (void)startRequestBody {

if (!self.started) {

self.started = YES;

[self setHTTPMethod:@"POST"];

NSString *format = @"multipart/form-data; boundary=%@";

NSString *contentType = [NSString stringWithFormat:format,

self.HTTPBoundary];

[self setValue:contentType forHTTPHeaderField:@"Content-Type"];

CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);

CFStringRef uuidStr = CFUUIDCreateString(kCFAllocatorDefault, uuid);

NSString *extension = @"multipartbody";

NSString *bodyFileName = [(NSString *)uuidStr

stringByAppendingPathExtension:extension];

CFRelease(uuidStr);

CFRelease(uuid);

self.pathToBodyFile = [NSTemporaryDirectory()

stringByAppendingPathComponent:bodyFileName];

NSString *bodyPath = self.pathToBodyFile;

self.bodyFileOutputStream = [NSOutputStream

outputStreamToFileAtPath:bodyPath

append:YES];

[self.bodyFileOutputStream open];

}

}

The form parameters are prepared in a similar fashion to what we did for Recipe 33, Format a Simple HTTP POST , except we don’t need to escape the values. Following the pattern in the sample body shown earlier, each parameter is preceded by the HTTP boundary and a Content-Disposition identifier. We build all the parameters as a single string that’s written out to the body as UTF-8 bytes. The UTF-8 conversion is done in the ‑appendBodyString: method.

MultipartHTTPPost/PRPMultipartPOSTRequest.m

NSMutableString *params = [NSMutableString string];

NSArray *keys = [self.formParameters allKeys];

for (NSString *key in keys) {

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

[params appendString:[self preparedBoundary]];

NSString *fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n";

[params appendFormat:fmt, key];

[params appendFormat:@"%@", [self.formParameters objectForKey:key]];

[pool release];

}

if ([params length]) {

if ([self

Return Main Page Previous Page Next Page

®Online Book Reader