Cocoa REAL SLOW NSTextView.有没有更好的方法将文本附加到NSTextView的内容?

the*_*olf 6 macos cocoa objective-c

我对Cocoa很新,这可能是一个完整的新问题.然而,我对死亡感到沮丧.

我有一个非常简单的Cocoa应用程序(称为"行")来测试向文本视图发送1000行文本.

我开始在Xcode 4中使用所有默认值的"新Cocoa项目".这给出了一个空白窗口对象,我可以在其上拖动IB UI元素.

我构建的UI包含一个文本视图和一个NIB文件窗口上的按钮.我正在使用Xcode 4将这两个元素拖到.h文件中.文本视图已连接,outView"1000"按钮连接到one_thousand_button方法.

用户界面

单击"1000"按钮会触发一个循环,将1000行文本("第1行\n""第2行\n"......"第1000行")打印到名为"outView"的NSTextView

这是整个代码(除了描述的.XIB文件):

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

执行起来非常慢.也许是第一次7秒,每次按"1000"时越来越慢.甚至还有旋转的彩色披萨!

我意识到这可能不是用1000行文本填充NSTextView的正确方法,并且读取文本视图内容并将其附加到stringByAppendingString方法的循环是瓶颈.

然而,另一种方法是什么?

结果

我包装了这段代码:

    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);
Run Code Online (Sandbox Code Playgroud)

围绕Adam Preble,我的原创和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
Run Code Online (Sandbox Code Playgroud)

第一轮比赛增加了1,000行; 第二次运行又添加了1000行等(Adam,base)是他的代码,没有beginEditingendEditing

很明显,使用beginEditingendEditing更快!

请参阅有关同步编辑的Apple文档.

Ada*_*ble 16

在调用beginEditing和中将更新包装到文本存储中endEditing.这会导致Cocoa保留所有更改通知,直到您完成对文本存储的更改.

- (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];
}
Run Code Online (Sandbox Code Playgroud)

在我的系统上,上述操作大约需要10毫秒.如果我注释掉对beginEditing/ 的调用endEditing,则需要大约470毫秒.