NSTimer + NSTask

Seth_

Registered
I'm trying to get the current upload and download bytes every X seconds from a netstat command. I'm using an NSTimer to launch a netstat process every time:
Code:
NSTimer *timer = [[NSTimer scheduledTimerWithTimeInterval: 5 
  target: uiHandler 
selector: @selector(refreshData:) 
userInfo: nil 
 repeats: YES] retain]; 
[timer fire];
refreshData currently only calls startTask:
Code:
- (void)startTask { 
aTask = [[NSTask alloc] init]; 
pipe = [[NSPipe pipe] retain]; 
   handle = [[pipe fileHandleForReading] retain]; 

[aTask setStandardOutput: pipe]; 
   [aTask setLaunchPath: @"/usr/sbin/netstat"]; 
   [aTask setArguments: args]; 
   [aTask launch]; 

/* ... */ 

[aTask terminate]; 
[aTask release]; 
aTask = nil; 

[pipe release]; 
pipe = nil; 

[handle release]; 
handle = nil; 
}
The first time the timer calls refreshData everything works. The second time I get this in the debugger:
Program received signal: "EXC_BAD_ACCESS".
Unable to disassemble objc_msgSend_rtp.
I'm not very experienced with Cocoa (as you may notice -- I come from Java). The release and retain count are equal so I don't think there should be a memory problem?
Thanks for the help.
 

frankf

Registered
Not enough information here. Give us some more of the information provided by the debugger. For example, what line the program crashes on, and a stack backtrace would be nice, too.

You need to read over retain/release some more. Everything is balanced, true, but unless you are going to use those objects again after the current runloop, then you don't need to send those retains/releases. Only retain something if you are going to use it outside the current runloop. If you do use those objects outside the current runloop, then it's quite possible that we don't have all the code we need to help you.
 

Krevinek

Evil PPC Tweaker
I can say this right now: the crash is not in the code you provided. The code, as written, should chug along just fine.
 

Seth_

Registered
The program crashes on [aTask launch]; when startTask is (indirectly) called for the second time by the timer. So... I think the crash really is in that part of the code? If you think you need the code of an other method or class, just ask.

The backtrace:
Code:
#0  0xfffeff18 in objc_msgSend_rtp ()
#1  0x9286a7a4 in -[NSConcreteTask setArguments:] ()
#2  0x00032928 in -[NetStats startTask] (self=0x353a70, _cmd=0x304520) at /Users/robin/Projects/Mini/NetStats.m:21
#3  0x00032a68 in -[NetStats refreshData] (self=0x353a70, _cmd=0x346010) at /Users/robin/Projects/Mini/NetStats.m:55
#4  0x0003ebe8 in -[UIHandler refreshData:] (self=0x345370, _cmd=0x3420e0, timer=0x3556a0) at /Users/robin/Projects/Mini/UIHandler.m:6
#5  0x9287fcfc in __NSFireTimer ()
#6  0x9075edb0 in __CFRunLoopDoTimer ()
#7  0x9074b728 in __CFRunLoopRun ()
#8  0x9074acdc in CFRunLoopRunSpecific ()
#9  0x93123be0 in RunCurrentEventLoopInMode ()
#10 0x931231ec in ReceiveNextEventCommon ()
#11 0x931230e0 in BlockUntilNextEventMatchingListInMode ()
#12 0x9362c1a4 in _DPSNextEvent ()
#13 0x9362be68 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#14 0x936283cc in -[NSApplication run] ()
#15 0x93718c1c in NSApplicationMain ()
#16 0x00012fa8 in main (argc=1, argv=0xbffffb0c) at /Users/robin/Projects/Mini/main.m:4

Unable to disassemble objc_msgSend_rtp.

Unable to disassemble objc_msgSend_rtp.
 

Seth_

Registered
This is weird. :eek:
If I don't fire the NSTimer, startTask gets executed right away and I get the same error that I normally get when the timer calls it for the second time.

This is what normally happens (with firing). I pass the PrefsHandler to uiHandler, and I create and fire the timer:
Code:
prefs = [[[PrefsHandler alloc] init] retain];
	[uiHandler setPrefsHandler:prefs];
	
	NSTimer *timer = [[NSTimer scheduledTimerWithTimeInterval: 5
			 target: uiHandler
			 selector: @selector(refreshData:)
			userInfo: nil
			repeats: YES] retain];
The timer calls [uiHandler refreshData: (NSTimer *) timer]:
Code:
 - (void)refreshData:(NSTimer *) timer {
	[netStats refreshData];

	[todaysDownloadField setIntValue: [netStats getDownload]];
	[todaysUploadField setIntValue: [netStats getUpload]];
	[todaysTotalField setIntValue: ([netStats getUpload]+[netStats getDownload])];
}
The, netStat's refreshData (yes I know, bad naming) calls netStat's startTask and sets the upload and download variables:
Code:
- (void)refreshData {
	[self startTask];
	download = [[(NSString *)[mutableListItems objectAtIndex:16] substringToIndex: [(NSString *)[mutableListItems objectAtIndex: 16] length]-1] intValue]/104857;
	upload = [[(NSString *)[mutableListItems objectAtIndex:19] substringToIndex: [(NSString *)[mutableListItems objectAtIndex: 19] length]-1] intValue]/104857;
}
The complete startTask looks like this:
Code:
- (void)startTask {	
	aTask = [[NSTask alloc] init];
	pipe = [[NSPipe pipe] retain];
    handle = [[pipe fileHandleForReading] retain];
	
	[aTask setStandardOutput: pipe];
    [aTask setLaunchPath: @"/usr/sbin/netstat"];
    [aTask setArguments: args];
    [aTask launch];

	// netstat lezen
	string = [[NSString alloc] initWithData: [handle readDataToEndOfFile]
								   encoding: NSASCIIStringEncoding];

	listItems = [string componentsSeparatedByString:@" "];
	
	mutableListItems = [[NSMutableArray alloc] init];
	
	NSEnumerator *enumerator = [listItems objectEnumerator];
	id element;
	int i = 0;
	while(element = [enumerator nextObject]) {
		if([element length]>0) {
			[mutableListItems addObject: element];
			NSLog(@"%@ (%d)", [mutableListItems objectAtIndex: i], i);
			i++;
		}
    }
	
	[aTask terminate];
	[aTask release];
	aTask = nil;
	
	[pipe release];
	pipe = nil;
	
	[handle release];
	handle = nil;
}
 
Top