Hi

I'm trying to write a general purpose console-like view and have most of the parts working except the convenience functions for adding attributed strings to an NSTextView subclass. Basically, what I want is to have a couple of functions that can be used like NSLog, but am finding that my functions seem to halt execution when they a re called from inside threads other than the main thread. I'm using "performSelectorOnMainThread:withObject:waitUntilDone:" to append the text to the NSTextView but this doesn't seem to be enough. Something I'm doing is causing a block somewhere when more than one thread tries to write to the NSTextView. If only one thread is created then my log function seems to work, but when two or more threads try to use the log functions, it locks up.

For the basic threading, I'm using NSOperationQueues and NSInvocationOperations and everything runs as expected when I use NSLog, but when I try to call my KCLog function, execution stops.

Could someone point out what I'm doing wrong in my log functions?

Here's the code that creates new operations and generates new ones when the operation completes. This code seems to work corectly when I replace my log functions with NSLog, but it's included in case there is some subtle (or not so subtle error) in how I'm using the queue/ operations.

- (void) updateOperation
{
        operation       = [[[NSInvocationOperation alloc]
                                                initWithTarget: self
                                                
selector:@selector(updateDirectories)
                                                object: nil]
                                                autorelease];
                                                
        [operation addObserver: self
                forKeyPath: @"isFinished"
                options: NSKeyValueObservingOptionNew
                context: NULL];
        
        [operationQueue addOperation: operation];
}

- (void) observeValueForKeyPath: inKeyPath
                ofObject: inObject
                change: inChange
                context: inContext
{
        if ([inKeyPath isEqualToString: @"isFinished"])
        {
                [operation removeObserver: self forKeyPath: @"isFinished"];
                
                sleep(catalogInterval);
                
                [self updateOperation];
        }
}

Here are the log functions:

void KCLog(id inMessage)
{
        [[KSharedConsole sharedConsole] addMessage: inMessage];
}

void KCLogColor(id inMessage, NSColor *inColor)
{
        [[KSharedConsole sharedConsole] addMessage: inMessage color: inColor];
}

Here are the shared console methods called by the functions

- (void) addMessage:(id) inMessage
{
// not sure if I need the synchronize, but I want it to work in threads and the more user friendly NSOperations
        // so I added it
        @synchronized(self)
        {
                [consoleView addMessage: inMessage];
        }
}

- (void) addMessage:(id) inMessage
                        color:(NSColor *) inColor
{
        @synchronized(self)
         {
                 [consoleView addMessage: inMessage color: inColor];
         }
}

Here is the console view interface
@interface KConsoleView : NSScrollView
{
        NSTextView                                      *textView;
        NSDictionary                            *timeAttributes;
        NSMutableDictionary                     *messageAttributes;
        NSString                                        *timestampFormat;
        
        unsigned int                            maxLength;
}

Here are the console view methods called by the shared console

- (void) addMessage:(id) inMessage
{
[self appendTime: [self styledTime] message: [self styledMessage: inMessage color: nil]];
}

- (void) addMessage:(id) inMessage
                        color:(NSColor *) inColor
{
[self appendTime: [self styledTime] message: [self styledMessage: inMessage color: inColor]];
}

And finally, here is the console view "appendTime:message:color" method that actually adds the message to the [textView textStorage] object

- (void) appendTime:(NSAttributedString *) inTime
                        message:(NSAttributedString *) inMessage
{
NSMutableAttributedString *styledLine = [[[NSMutableAttributedString alloc] init] autorelease];
        
        // don't let the string get too big
        if ([[textView textStorage] length] > maxLength)
        {
                // time to flush console
NSMutableAttributedString *styledFlush = [[[NSMutableAttributedString alloc] init] autorelease];
                
                NSMutableDictionary                     *tempStyle              
= [messageAttributes mutableCopy];
[tempStyle setObject: [NSColor redColor] forKey: NSForegroundColorAttributeName];
        
                NSAttributedString                      *flushMessage   = 
[[[NSAttributedString alloc]
                                                                                          
                              initWithString: @"Flushed console\r"
                                                                                
                                        attributes: tempStyle]
                                                                                
                                        autorelease];
                
                [styledFlush appendAttributedString: inTime];
                [styledFlush appendAttributedString: flushMessage];
        
                // replace the entire contents with the flush message
        [[textView textStorage]
performSelectorOnMainThread: @selector(setAttributedString:)
                withObject: styledFlush
                waitUntilDone: YES];
        }
        
        // build user message
        [styledLine appendAttributedString: inTime];
        [styledLine appendAttributedString: inMessage];
        
        // add user message to text storage
    [[textView textStorage]
performSelectorOnMainThread: @selector(appendAttributedString:)
            withObject: styledLine
            waitUntilDone: YES];
        
        // adjust scroll
[textView scrollRangeToVisible: NSMakeRange([[textView textStorage] length], 0)];
    [textView display];
}



_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to