NSTextView not refreshed in a loop when writing to a USB device

I am writing an Objective-C application that communicates with a USB device. The application continuously writes specific data to the device and displays the status of the write operation in a text element, which is an NSTextView object. I am calling the method -[NSTextView insertText:]

in a loop when I get the status of a write operation from a device.

The problem is that the NSTextView is not refreshed on every call -insertText:

. I only get the entire content of the NSTextView after the whole loop has been done.

I have not seen an appropriate update or update method for the NSTextView class. How can I get the status of the operation and update the NSTextView at the same time?

- (IBAction)notifyContentHasChanged:(NSInteger) block {
    NSString *str;
    str = [NSString stringWithFormat:@"Block Written Successfully: %d\n", block];
    [data insertText:str];
}

- (IBAction)func {
    while(USB_SUCCESS(status))
    {
        printf("\nBlocks Written Successfully: %d",BlockCnt);
        [refToSelf notifyContentHasChanged:BlockCnt];
    }
}

      

Note that the console printf

on the console is updated in a timely manner, but not the NSTextView.

+1


source to share


4 answers


Mac OS X does not flush changes to screen views immediately to avoid the flickering and tearing that usually occurs in these situations. This means that you cannot just sit in a loop and perform blocking operations while updating the view; if you do this, neither the view nor anything else in the human interface of your application will be updated and your application will display in the hang and end up with a rotating cursor.

(A spinning cursor appears when the application does not contact the window server after a short amount of time, and there is no way to suppress it by design. This does not mean "wait", it means "this application has gone into the weed" and you should strive to it never showed up for your users.)



To control blocking operations in Cocoa, you can do one of two things:

  • You can perform blocking operations on a background thread and pipe the results to the main thread to update your human interface. For example, you can do I / O or socket communication using select(2)

    UNIX file I / O and standard file I / O calls.

  • You can schedule activities in a run loop (such as a main run loop) if a compatible version is available; this will usually run a background thread for the blocking version of the operation for you. For example, NSFileHandle provides a consistent loop-dependent paragraph on top of file descriptors; NSStream does this for sockets as well.

+4


source


You will need to use:

//Creates the background thread.
dispatch_queue_t backgroundQueue = dispatch_queue_create("Network", nil);

      

To create a new thread. Then wrap your code like this:

//Runs code in background thread.
dispatch_async(backgroundQueue, ^(void){
    //Code Here.
});

      



And the updated UI should be wrapped in:

//Sends code within the background thread to the main thread.
dispatch_async(dispatch_get_main_queue(), ^(void){
    //Code Here.
});

      

So in your code:

- (IBAction)notifyContentHasChanged:(NSInteger) block {
    NSString *str;
    str = [NSString stringWithFormat:@"Block Written Successfully: %d\n", block];
    [data insertText:str];
}

- (IBAction)func {
    dispatch_queue_t backgroundQueue = dispatch_queue_create("Network", nil);
    dispatch_async(backgroundQueue, ^(void){
        while(USB_SUCCESS(status))
        {
            printf("\nBlocks Written Successfully: %d",BlockCnt);
            dispatch_async(dispatch_get_main_queue(), ^(void){
                [refToSelf notifyContentHasChanged:BlockCnt];
            });
        }
    });
}

      

+1


source


You can update the NSTextView using the -setNeedsDisplay: method.

0


source


I have a loop that accesses data from the network and fills it in a db. Since I am processing, I would like to have a console window (not one in Xcode, since that would be a compiled application.)

So, I have an NSTextView that I change the textStorage and scroll to the end each time. Unfortunately, only visible changes occur when the loop is complete (although true.)

Is there some simple "OK, refresh screen now" method without having to get low or write a lot more code?

-1


source







All Articles