When you allocate objects using factory methods, the objects are added to the autoreleasepool. The autoreleasepool is only drained when your event loop runs, after your IBAction
has returned.
The trick here would be to put the contents of your loop in its own autorelasepool.
But let's address the biggest problem first. There's a NSMutableString class that you should use here, which would drastically reduce the number of objects you need to create.
We'll switch completeFile to a NSMutableString, constructed using a factory method, then append to it:
-(void) writeToFile: (NSString*)filePath withSeparator:(NSString*) fieldSep{
NSMutableString* completeFile = [NSMutableString string];
for(int i=0;i<[self numberOfRows];i++){
printf("im at line number... %i of %i\n",i,[self numberOfRows]);
for(int j=0;j<[self numberOfColumns];j++){
[completeFile appendString:[self objectInRow:i column:j]];
if(j<[self numberOfColumns]-1){
//separator for all columns except last one
completeFile appendString:fieldSep];
}
}
[completeFile appendString:@"\n"];
}
NSError *error = nil;
[completeFile writeToFile:filePath atomically:NO
encoding:NSStringEncodingConversionAllowLossy error:&error];
if(error){
NSLog(@"Error writing file at %@\n%@",
filePath, [error localizedFailureReason]);
}
}
This leaves another problem, though. See that [self objectInRow:i column:j]
? It's still (presumably) an autoreleased object. That won't get cleaned up.
We may have made your code run without crashing, depending on the size of the data, but it's a question of when it crashes not if.
To fix this, we need to introduce autoreleasepools. Let's do one per row and per column. This might seem excessive (and, indeed, it is in this case since we've eliminated autoreleasepool use in the outer loop) but autoreleasepools are pretty cheap. If you're doing a loop over a large amount of data, it's just good practice.
You can replace each of your for blocks with @autorelease
blocks, for instance:
for(int i=0;i<[self numberOfRows];i++){
With:
for(int i=0;i<[self numberOfRows];i++) @autoreleasepool {
That gives us this code:
-(void) writeToFile: (NSString*)filePath withSeparator:(NSString*) fieldSep{
NSMutableString* completeFile = [NSMutableString string];
for(int i=0;i<[self numberOfRows];i++) @autoreleasepool {
printf("im at line number... %i of %i\n",i,[self numberOfRows]);
for(int j=0;j<[self numberOfColumns];j++) @autoreleasepool {
[completeFile appendString:[self objectInRow:i column:j]];
if(j<[self numberOfColumns]-1){
//separator for all columns except last one
completeFile appendString:fieldSep];
}
}
[completeFile appendString:@"\n"];
}
NSError *error = nil;
[completeFile writeToFile:filePath atomically:NO
encoding:NSStringEncodingConversionAllowLossy error:&error];
if(error){
NSLog(@"Error writing file at %@\n%@",
filePath, [error localizedFailureReason]);
}
}
A final note, though. Your error check here is not safe. What happens to an error pointer passed in like this on success isn't defined.
[completeFile writeToFile:filePath atomically:NO
encoding:NSStringEncodingConversionAllowLossy error:&error];
if(error){
NSLog(@"Error writing file at %@\n%@",
filePath, [error localizedFailureReason]);
}
Instead, you want this:
BOOL ok = [completeFile writeToFile:filePath atomically:NO
encoding:NSStringEncodingConversionAllowLossy error:&error];
if(!ok){
NSLog(@"Error writing file at %@\n%@",
filePath, [error localizedFailureReason]);
}
This, then, should do what you want.