Cocoa REAL SLOW NSTextView. Is there a better way to add text to the contents of an NSTextView?

I am very new to Cocoa and this is probably the complete newb question. However, I am upset to death.

I have an extremely simple Cocoa application (called "lines") to verify that 1000 lines of text are sent to a text view.

I started in Xcode 4 with the โ€œnew Cocoa projectโ€ with all the defaults. This gives an empty window object on which I can drag and drop IB UI elements.

Then, the constructed user interface consists of a text view and a button in the NIB file window. I am using Xcode 4 to drag these two elements into a .h file. The text view is connected to the outView , and the "1000" button is connected to the one_thousand_button method.

The ui

Pressing the "1000" button starts a cycle to print 1000 lines of text ("line 1 \ n" "line 2 \ n" ... "line 1000") in an NSTextView called "outView"

Here is all the code (except the described .XIB file):

linesAppDelegate.h:

 #import <Cocoa/Cocoa.h> @interface linesAppDelegate : NSObject <NSApplicationDelegate> { @private NSWindow *window; NSTextView *outView; } @property (assign) IBOutlet NSWindow *window; @property (assign) IBOutlet NSTextView *outView; - (IBAction)one_thousand_button:(id)sender; @end 

linesAppDelegate.m:

 #import "linesAppDelegate.h" @implementation linesAppDelegate @synthesize window; @synthesize outView; - (IBAction)one_thousand_button:(id)sender { NSString* oldString; NSString* newString; for(int i=1; i<=1000; i++){ oldString = [outView string]; newString = [oldString stringByAppendingString: [NSString stringWithFormat: @"Line %i\n",i]]; [outView setString: newString]; } } @end 

This is REALLY SLOW to execute. Maybe 7 seconds for the first time and slower each time you press "1000". There is even a spinning colorful death pizza!

I understand that this is probably the wrong way to populate an NSTextView with thousands of lines of text, and that a loop that reads the contents of a text view and adds it using the stringByAppendingString method is a bottleneck.

What is an alternative method?

Result

I wrapped this code:

  mach_timebase_info_data_t info; mach_timebase_info(&info); uint64_t start = mach_absolute_time(); // timed code uint64_t duration = mach_absolute_time() - start; duration *= info.numer; duration /= info.denom; duration /= 1000000; NSLog(@"timed code took %lld milliseconds!", duration); 

around the Adam Preble code, my original and drewk :

  Adam Preble (Adam, base) drewk my pitiful code 1st run: 3ms 269ms 260ms 1,950ms 2nd run 3ms 269ms 250ms 2,332ms 3rd run: 2ms 270ms 260ms 2,880ms 

The first run adds 1000 lines; The second run adds another 1000 lines, etc. (Adam, base) is his code without beginEditing and endEditing

Clearly using beginEditing and endEditing is faster!

See Apple docs for Sync Editing .

+6
objective-c cocoa macos
source share
2 answers

Wrap updates in text storage with beginEditing and endEditing . This will cause Cocoa to keep all its change notifications until you finish making changes to the text store.

 - (IBAction)oneThousandButton:(id)sender { NSTextStorage *textStorage = [outView textStorage]; [textStorage beginEditing]; for (int i = 1; i <= 1000; i++) { NSString *line = [NSString stringWithFormat: @"Line %i\n", i]; [textStorage replaceCharactersInRange:NSMakeRange([textStorage length], 0) withString:line]; } [textStorage endEditing]; } 

On my system, the indicated action takes about 10 ms to complete. If I comment on the beginEditing / endEditing , it will take about 470 ms.

+16
source share

Try the following:

 - (IBAction)one_thousand_button:(id)sender { for(int i=1; i<=1000; i++){ [[[outView textStorage] mutableString] appendString: [NSString stringWithFormat: @"Line %i\n",i]]; } } 

There is an invaluable "quickie" link to Objective-C HERE with the included NSTextView HERE.

Best...

+3
source share

All Articles