我有一个非常简单的玩具应用程序,只有一个文本视图和一个按钮。
这些由AppController类控制,看起来像这样
// AppController.h
#import <Cocoa/Cocoa.h>
@interface AppController : NSObject <NSTextViewDelegate>
@property IBOutlet NSTextView *textView;
-(IBAction)apply:(id)sender;
@end
// AppController.m
#import "AppController.h"
@implementation AppController {
NSString *name;
}
-(void)awakeFromNib {
name = @"Bob";
_textView.string = name;
}
-(IBAction)apply:(id)sender {
name = _textView.string;
NSLog(@"%@", name);
}
-(void)textDidChange:(NSNotification *)notification {
NSLog(@"%@", name);
}
@end
当用户在textView中输入新值并单击“应用”按钮时,我希望实例变量名称获取此新值。这是我第一次点击“应用”按钮时发生的情况。
但是下次我更改textView中的值时,实例变量会自动更改,而无需用户点击“应用”按钮!
这是一种不受欢迎的行为,因为我没有进行任何绑定。事实上,如果我将textView更改为textField,则不会发生奇怪的行为。
所以似乎NSTextView做了一些奇怪的非自愿绑定。有人可以解释这种奇怪的行为以及如何解决这个问题。我不希望textView在我背后改变我的数据。
我在YouTube上制作了一个视频,其中显示了textField和textView之间的行为差异,您可以在https://youtu.be/qenGKp_L4qs找到它。
我已经检查了Xcode6和Xcode5,并且两者都发生了奇怪的行为。
如果您想在自己的机器上测试它,请不要忘记将NSTextView的委托属性与IB中的AppController连接。
答案 0 :(得分:4)
这一行:
name = _textView.string;
使您的实例变量引用文本视图在内部使用的同一对象。来自documentation for the string
property of NSText
(NSTextView
继承自:)
出于性能原因,此方法返回文本对象的当前后备存储。如果要在操作文本存储时维护此快照,则应复制相应的子字符串。
当你说'#34;我不希望textView改变我背后的数据时,你就错了。文本视图正在更改其数据,您(不明智地)将其视为您自己的数据。
你应该a)为你的内部状态创建一个(可能是私有的)属性,b)使用该属性的copy
属性,c)使用self.name = _textView.string;
分配给你的内部状态。< / p>
如果您不想这样做,则必须至少使用name = [_textView.string copy];
手动复制字符串。