1

Context

I want to send an HTTP request with multipart body data composed by two segments:

  1. A JSON string containing some metadata
  2. Some file binary data

What I already know

This can be done easily as described in this answer. But what happens in a situation where the file can be potentially large? With this new constraint, we naturally can't encapsulate the data in a NSData object, as it would take a lot of memory resources.

The first idea that anyone familiar with the NSURLRequest class would have is to use the HTTPBodyStream property instead of HTTPBody. But how is it possible to get a stream that would write both JSON and file data segments (as well as the boundaries and the other required HTTP stuff)?

The way out would be to subclass NSInputStream. In fact I've noticed that the AFNetworking framework uses this approach. But from I've heard, there are a lot of undocumented/weird methods to override from the NSStream class, as described here, which, in my humble opinion, sounds like a lot of (potentially dangerous) work needed to achieve something apparently simple.


Question

Is there a way to achieve the desired behaviour? Please consider the following constraints:

  • No third party frameworks
  • Using a clean method (not overriding undocumented methods, as they can change on future SDKs)
Community
  • 1
  • 1
Gabriel Huff
  • 743
  • 1
  • 6
  • 18

1 Answers1

1

You can use my open sourced POSInputStreamLibrary. It provides ability to stream any data you want. The only thing you need to do is to implement POSBlobInputStreamDataSource protocol and use implementation as an argument of POSBlobInputStream.

If you strongly restricted using 3rd party frameworks you can use POSBlobInputStream as an example which implements private API methods to make custom NSInputStream workable.

Feel free to ask any questions about implemetation details and good luck.

Pavel Osipov
  • 2,067
  • 1
  • 19
  • 27
  • Thanks for your answer. This looks like an interesting approach and I guess it would solve my problems. But I was taking a look at your POSBlobInputStream class implementation and found that you haven't implemented the '_scheduleInCFRunLoop:forMode:', '_setCFClientFlags:callback:context:' and '_unscheduleFromCFRunLoop:forMode:' methods. These are the 'dangerous undocumented' methods that I mentioned in my question. From what I've read in this link: http://blog.bjhomer.com/2011/04/subclassing-nsinputstream.html they can cause the app to crash – Gabriel Huff Nov 24 '15 at 12:19
  • But of course, I haven't implemented anything yet. From your experience, do you think that NSInputStream subclasses should work properly without implementing these methods? – Gabriel Huff Nov 24 '15 at 12:21
  • Thanks for a question, @GabrielHuff. The magic is in the method `resolveInstanceMethod:`. It cuts '_' prefix in incomming unknown selectors and tries to redirect invokation to the methods without it. You can look at companions of `_scheduleInCFRunLoop:forMode:`, `_setCFClientFlags:callback:context:` and `_unscheduleFromCFRunLoop:forMode:` without underscore in [POSBlobInputStream.m](https://github.com/pavelosipov/POSInputStreamLibrary/blob/master/POSInputStreamLibrary/POSBlobInputStream.m) – Pavel Osipov Dec 01 '15 at 08:06