I am very new to Cocoa and this is probably a complete newb question. I am frustrated to death however.
I have an extremely simple Cocoa app (called "lines") to test sending 1000 lines of text to a text view.
I started in Xcode 4 with "new Cocoa project" with all the defaults. This gives a blank window object upon which I can drag IB UI elements.
The UI I then constructed consists of a Text View and a button on the window of a NIB file. I am using Xcode 4 to drag those two elements to the .h file. The text view is connected to outView
and the "1000" button is connected to one_thousand_button
method.
Clicking the button "1000" triggers a loop to print 1,000 lines of text ("line 1\n" "line 2\n" ... "line 1000") to the NSTextView called "outView"
Here is the entire code (other than the .XIB file described):
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. Perhaps 7 seconds the first time and increasingly slow with each press of "1000". Even has the spinning colorful pizza of death!
I realize that this is probably not the right way to fill a NSTextView with 1,000 lines of text and that the loop that read the contents of the text view and appends that with stringByAppendingString
method is the bottleneck.
What is the alternative method however?
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 code from Adam Preble, 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 1,000 lines; 2nd run adds another 1,000 lines, etc. (Adam, base) is his code without the beginEditing
and endEditing
It is clear that using beginEditing
and endEditing
is WAY faster!
See the Apple documents on Synchronizing Editing.
NSTextView
itself but rather that you're allocating 2 new strings every time you loop (1 via thestringWithFormat:
and the other as the result ofstringByAppendingString:
) and then changing the string of the textView every iteration. @drewk's answer should really help to speed this up. – Dave DeLong