NSTimer never starts
Asked Answered
O

1

9

I'm just trying to close an NSPanel after a couple second delay, but I can't get my NSTimer to start. It will fire if I explicitly call the fire method on it, but it will never go by itself. Here's my code:

   - (void)startRemoveProgressTimer:(NSNotification *)notification {
    NSLog(@"timer should start");
    timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(removeProgress:) userInfo:nil repeats:NO];
}

- (void)removeProgress:(NSTimer *)timer {
    [progressPanel close];
}

I do have some threading in my code as such. I assume this is what's messing my timer up.

-(void)incomingTextUpdateThread:(NSThread*)parentThread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

//mark the thread as running
readThreadRunning = TRUE;

const int BUFFER_SIZE = 100;
char byte_buffer[BUFFER_SIZE]; //buffer for holding incoming data
int numBytes = 0; //number of bytes read
NSString *text; //incoming text from the serial port

[NSThread setThreadPriority:1.0];

//this will loop until the serial port closes
while (TRUE) {
    //read() blocks until some data is available or the port is closed
    numBytes = read(serialFileDescriptor, byte_buffer, BUFFER_SIZE);
    if(numBytes > 0) {
        //creat a string from the incoming bytes
        text = [[[NSString alloc] initWithBytes:byte_buffer length:numBytes encoding:[NSString defaultCStringEncoding]] autorelease];
        if(!([text rangeOfString:SEND_NEXT_COORDINATE].location == NSNotFound)) {
            //look for <next> to see if the next data should be sent
            if(coordinateNum <[coordinatesArray count]) {
                [self sendNextCoordinate]; //send coordinates
            }
            else {
                [self writeString:FINISH_COORDINATES_TRANSMIT]; //send <end> to mark transmission as complete
                NSNumber *total = [NSNumber numberWithUnsignedInteger:[coordinatesArray count]];
                NSDictionary *userInfo = [NSDictionary dictionaryWithObject:total forKey:@"progress"];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"uploadProgressChange" object:self userInfo:userInfo]; //update progress bar to completed
            }


        }

        [self performSelectorOnMainThread:@selector(appendToIncomingText:) withObject:text waitUntilDone:YES]; //write incoming text to NSTextView
    } else {
        break; //Stop the thread if there is an error
    }
}

// make sure the serial port is closed
if (serialFileDescriptor != -1) {
    close(serialFileDescriptor);
    serialFileDescriptor = -1;
}

// mark that the thread has quit
readThreadRunning = FALSE;

// give back the pool
[pool release];
}

Which is called from another method by: [self performSelectorInBackground:@selector(incomingTextUpdateThread:) withObject:[NSThread currentThread]];

Overwinter answered 6/2, 2011 at 5:36 Comment(4)
Hmm... don't see anything wrong, but why are you passing the currentThread as the withObject: parameter? You don't seem to use it in that method, why not just pass nil?Boring
A suspicion I have (just a suspicion, since I can't see what calls startRemoveProgressTimer:) scheduledTimerWithTimeInterval adds the timer to the current thread's run loop, not the main thread's. If you're creating your timer in a background thread that never uses its run loop -- if just sits and spins in a while(1) loop reading from a file descriptor, say -- the run loop never gets a chance to deal with any queued-up timers. Try explicitly adding it to the main thread's run loop instead and see what happens.Teerell
Would it make a difference if I told you that startRemoveProgressTimer: is tied to a NSNotification? As to why I am passing in current thread, I'm not sure. I'm trying to adapt somebody else's code to my application. The original code is here: arduino.cc/playground/Interfacing/Cocoa but I had to make some modifications to get it to compile on (Snow) Leopard, and I put in some of my own logic.Overwinter
I think there's something wrong with your notifications. Can you post your notification code as well, please? (There is no reason that if startRemoveProgressTimer is called that your timer should not fire)Glasgo
O
18

Thank you rgeorge!!

Adding the timer to the run loop manually made it work!

timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(removeProgress:) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
Overwinter answered 6/2, 2011 at 16:6 Comment(1)
Specifically, adding it to the main (main thread's) run loop. The scheduledTimer… methods add the timer to the run loop, but they add it to the current (current thread's) run loop. It would also have worked to do a main-thread perform that you respond to by creating/scheduling the timer.Wrestle

© 2022 - 2024 — McMap. All rights reserved.