IOS: How to avoid autorealized copies when working with a large instance of NSString?

I have a script in an iOS application where manipulating a very large instance of NSString (HTTP response, above 11 MB) causes several large intermediaries to be in memory immediately, since the SDK methods that I call return new instances with auto-implementation . What is the best approach for this?

For example, assuming that largeString is an instance of NSString with auto-implementation:

 NSArray *partsOfLargeString = [largeString componentsSeparatedByString:separator]; for (NSString *part in partsOfLargeString) { NSString *trimmedPart = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSData *data = [trimmedPart dataUsingEncoding:NSUTF8StringEncoding]; } 

It would be great if there were unrealized equivalents of componentsSeparatedByString or stringByTrimmingCharactersInSet , but I'm not going to implement them myself.

As far as I know, there is no way to "force" to free an object that has already been added to the autorun pool. I know that I can create and use my own autoresource pool here, but I would like to be extremely granular and have autorun pools around individual operators, definitely not a very scalable approach.

Any suggestions are greatly appreciated.

+7
source share
2 answers

As Bill said, Id will first try to create an autostart pool for each iteration of the loop, for example:

 for (NSString *part in partsOfLargeString) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSString *trimmedPart = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSData *data = [trimmedPart dataUsingEncoding:NSUTF8StringEncoding]; … [pool drain]; } 

or, if you use a fairly recent compiler:

 for (NSString *part in partsOfLargeString) { @autoreleasepool { NSString *trimmedPart = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSData *data = [trimmedPart dataUsingEncoding:NSUTF8StringEncoding]; … } } 

If this is still unacceptable and you need to unlock the objects in more detail, you can use something like:

 static inline __attribute__((ns_returns_retained)) id BICreateDrainedPoolObject(id (^expression)(void)) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; id object = expression(); [object retain]; [pool drain]; return object; } #define BIOBJ(expression) BICreateDrainedPoolObject(^{return (expression);}) 

which evaluates the expression, saves its result, frees any auxiliary objects with auto-implementation and returns the result; and then:

 for (NSString *part in partsOfLargeString) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSString *trimmedPart = BIOBJ([part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]); NSData *data = BIOBJ([trimmedPart dataUsingEncoding:NSUTF8StringEncoding]); [trimmedPart release]; // do something with data [data release]; … [pool drain]; } 

Please note: since the function returns a stored object, you are responsible for freeing it. When you do this, you will have control.

Feel free to choose the best names for function and macro. There may be some corner cases that should be handled, but they should work for your specific example. Suggestions are welcome!

+2
source

First, you do not need to parse the responses from the HTTP server in this way. Parsing HTTP responses (including HTML parsing) is a solvable problem, and trying to parse it using crude string processing will result in fragile code that can easily be broken with seemingly harmless changes on the server side.

Pools of abstracts are quite cheap. You can surround the body [inside] of the with @autoreleasepool {... that code ...} , and this will probably fix your problem with high water levels and have a slight impact on performance [compared to raw string processing ].

In addition, your resume is correct - if the set does not have an option without an autoresistor, you will have to reinvent the wheel. In view of the foregoing, it is quite typical that the absence of an option without an autoresistor is not supervised by the designer. Instead, it is most likely because there are better tools available to achieve such a large-scale solution that will also require finer memory management.

+1
source

All Articles