我在Xcode中创建了一个新的Cocoa应用程序项目,然后在窗口上添加了NSOutlineView和NSTextView对象。这两个对象被子类化为MyOutlineView和MyTextView。之后,我为他们创建了两个出口,并编写了如下代码。
我发现,问题是应用程序在运行时有两个不同的MyOutlineView实例。工作(有效)大纲视图实例不等于myOutlineView插座实例。我错过了什么?
//
// AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "MyOutlineView.h"
#import "MyTextView.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet MyOutlineView *myOutlineView;
@property (unsafe_unretained) IBOutlet MyTextView *myTextView;
@end
//
// AppDelegate.m
#import "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)n
{
NSLog(@"AppDelegate.myOutlineView(INVALID)::%@", _myOutlineView);
NSLog(@"AppDelegate.myTextView::%@", _myTextView);
}
@end
//
// MyOutlineView.h
#import <Cocoa/Cocoa.h>
@interface MyOutlineView : NSOutlineView <NSOutlineViewDataSource>;
@end
//
// MyOutlineView.m
#import "MyOutlineView.h"
@implementation MyOutlineView
- (id)initWithCoder:(NSCoder *)aDecoder
{
// This method is called first.
self = [super initWithCoder:aDecoder];
NSLog(@"MyOutlineView initWithCoder(INVALID)::%@", self);
return self;
}
- (id)initWithFrame:(NSRect)frame
{
// This method is also called but through a different instance with first one.
self = [super initWithFrame:frame];
NSLog(@"MyOutlineView initWithFrame(valid)::%@", self);
return self;
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
NSLog(@"MyOutlineView data source delegate(valid)::%@", self);
return 0;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
return nil;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
return NO;
}
@end
//
// MyTextView.h
#import <Cocoa/Cocoa.h>
@interface MyTextView : NSTextView
@end
//
// MyTextView.m
#import "MyTextView.h"
@implementation MyTextView
- (id)initWithCoder:(NSCoder *)aDecoder
{
// This method is called.
self = [super initWithCoder:aDecoder];
NSLog(@"MyTextView initWithCoder::%@", self);
return self;
}
- (id)initWithFrame:(NSRect)frame
{
// But this method is NOT called at all.
self = [super initWithFrame:frame];
NSLog(@"MyTextView initWithFrame::%@", self);
return self;
}
@end
输出:
MyTextView initWithCoder:: [MyTextView: 0x10013be80]
MyOutlineView initWithCoder(INVALID):: [MyOutlineView: 0x10014bc90]
MyOutlineView initWithFrame(valid):: [MyOutlineView: 0x1001604a0]
MyOutlineView data source delegate(valid)::[MyOutlineView: 0x1001604a0]
AppDelegate.myOutlineView(INVALID):: [MyOutlineView: 0x10014bc90]
AppDelegate.myTextView:: [MyTextView: 0x10013be80]
因此,我必须把“AppDelegate.myOutlineView = self;”进入MyOutletView的实现,只要它调用AppDelegate的相关方法。这似乎并不自然。
答案 0 :(得分:2)
Xcode似乎不允许您将大纲视图的委托或数据源设置为自身。
所以我猜你正在做这样的事情:
也就是说:实例化自定义大纲视图类的第二个副本。
以下是此设置的输出:
2012-09-26 14:11:34.511 testproj[30255:403] -[MyOutlineView initWithCoder:]
2012-09-26 14:11:34.531 testproj[30255:403] -[MyOutlineView initWithFrame:]
通过删除“我的大纲视图”的额外(突出显示)实例,initWithFrame:
行消失。
要使大纲视图成为自己的委托,请改为:
- (void) awakeFromNib {
self.delegate = self;
}
尽管如此,委托模式的重点是避免了子类化的需要。如果做需要大纲视图子类,请尝试直接覆盖NSOutlineView / NSTableView方法,而不是使用委托协议。
答案 1 :(得分:1)
我无法重现你的问题。我将您发布的所有代码都放到了测试应用程序中,我只获得了每个对象的一个实例。我尝试时都没有调用initWithFrame方法。我的输出是:
2012-09-26 09:00:38.945 TextViewDoubleInstantiationProblem[451:303] MyTextView initWithCoder::<MyTextView: 0x100123990>
Frame = {{0.00, 0.00}, {381.00, 182.00}}, Bounds = {{0.00, 0.00}, {381.00, 182.00}}
Horizontally resizable: NO, Vertically resizable: YES
MinSize = {381.00, 182.00}, MaxSize = {463.00, 10000000.00}
2012-09-26 09:00:38.953 TextViewDoubleInstantiationProblem[451:303] MyOutlineView initWithCoder(INVALID)::<MyOutlineView: 0x101a1cb90>
2012-09-26 09:00:39.005 TextViewDoubleInstantiationProblem[451:303] AppDelegate.myOutlineView(INVALID)::<MyOutlineView: 0x101a1cb90>
2012-09-26 09:00:39.005 TextViewDoubleInstantiationProblem[451:303] AppDelegate.myTextView::<MyTextView: 0x100123990>
Frame = {{0.00, 0.00}, {381.00, 182.00}}, Bounds = {{0.00, 0.00}, {381.00, 182.00}}
Horizontally resizable: NO, Vertically resizable: YES
MinSize = {381.00, 182.00}, MaxSize = {463.00, 10000000.00}
您的应用中是否还有其他未显示的代码?
答案 2 :(得分:0)
对initWithCoder:
的调用来自加载nib文件中定义的对象。我认为,自从你提到创建网点以来,这就是你想要发生的事情。在这种情况下,他们打电话给initWithFrame:
让我觉得比编码员更有可能“无效”。
我在initWithFrame:
设置了一个断点,并跟踪该来电的来源,以确定额外的分配。