I am trying to run a simple shell command that runs and returns text rather quickly inside of a loop of indeterminate size at compile time that is generated by an NSArray. In scripting languages like perl, I would be able to do something like this:
for(i=0;i<=$myinputarraysize;i++){
$output[i]=`/my/task $inputarray[i]`;
}
This would build a new array for me from the expected output of my task. In Obj-C this seems to be much more difficult and a bit confusing to me. Right now my loop looks like this:
for(int i=0; i<[inputarray count]; i++){
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath:nsdchat];
NSArray *args;
args = [NSArray arrayWithObjects:@"/my/task", [inputarray objectAtIndex:i], nil];
[task setArguments:args];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *desc;
desc = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
desc = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
[descriptions insertObject:desc atIndex:i];
[task release];
[args release];
[pipe release];
[file release];
[data release];
}
My goal is to fill descriptions (an NSMutableArray) with the output from my task (which I know is always a string and always ends in a newline that I want to strip out). It seems I'm missing something about memory releasing as when I run this and NSLog the output, I get the same result for the entire count of the loop.
Is there any easier or more way to loop through simple tasks like this? Am I overcomplicating it for myself?
First of all, there's no need to do most of that work inside the loop. task
, pipe
and file
all look like they could be handled outside the loop. You should also consider using Objective-C 2.0 dot syntax and fast enumeration to cut things down a little.
More significantly:
NSArray *args;
args = [NSArray arrayWithObjects:@"/my/task", [inputarray objectAtIndex:i], nil];
[task setArguments:args];
This says that the first argument passed to the executable at path ndschat
is /my/task
. Which doesn't seem to match your PERL usage. Probably you want just:
NSArray *args;
args = [NSArray arrayWithObject:[inputarray objectAtIndex:i]];
[task setArguments:args];
Or, with the style comments taken into account:
for(NSString *argument in inputarray)
{
...
task.arguments = [NSArray arrayWithObject:argument];
...
}
EDIT: you're also releasing a lot of objects you don't own, which as well as adding heft to your code is a memory management error possibly leading to a crash. So, to cut the whole thing down and correct that fault:
for(NSString *argument in inputarray)
{
NSTask *task = [[NSTask alloc] init]; // you now own this
task.launchPath = nsdchat;
NSPipe *pipe = [NSPipe pipe]; // you don't own this
task.standardOutput = pipe;
NSFileHandle *file = [pipe fileHandleForReading]; // you also don't own this
task.arguments = [NSArray arrayWithObject:argument];
[task launch];
[task waitUntilExit]; // you should wait until the task is done
NSData *data = [file readDataToEndOfFile]; // this is another thing
// you don't own. Note also that
// readDataToEndOfFile advances
// the current read pointer, so
// it should be fine to do this
// successively
NSString *desc;
desc = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
autorelease];
// you don't own this because
// of the autorelease; you
// don't want to own it since
// the next line will throw
// it away
desc = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
// you don't own this
[descriptions addObject:desc];
[task release];
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.