LeftPaneViewController

LeftPaneViewController

我的意图是为带有两个窗格的NSSplitView提供2个单独的 View Controller 。在左窗格中,我需要一个表格 View ,但是它崩溃了。这是场景:

我有一个带有MainMenu.xib,AppDelegate.h / m的简单项目。在此项目中,我添加了LeftPaneViewController.h / .m / .xib。

在MainMenu.xib中,我将NSSplitView添加到默认 View 。

在AppDelegate.h中:

@property (weak) IBOutlet NSSplitView *splitView;

在AppDelegate.m中:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   // Insert code here to initialize your application
   LeftPaneViewController *lpvc = [[LeftPaneViewController alloc]   initWithNibName:@"LeftPaneViewController" bundle:nil];
   [self.splitView replaceSubview:[[self.splitView subviews] objectAtIndex:0] with:lpvc.view];
}

我将MainMenu.xib中的NSSplitView连接到AppDelegate中的splitView。

当我运行时,这很好,但是当然没有什么可看的了。

在LeftPaneViewController.xib中,我将NSTableView添加到默认的自定义 View 。我删除其中一列(列表底部的一列)。

在LeftPaneViewController.h中:
@interface LeftPaneViewController : NSViewController <NSTableViewDelegate, NSTableViewDataSource>

@property (weak) IBOutlet NSTableView *tableView;
@property (nonatomic, retain) NSMutableArray *tableDataSource;

在LeftPaneViewController.m中:
#import "LeftPaneViewController.h"

@interface LeftPaneViewController ()

@end

@implementation LeftPaneViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialization code here.
    }
    return self;
}

- (void)awakeFromNib
{
    self.tableDataSource = [[NSMutableArray alloc] initWithObjects:@"Row1", @"Row2", nil];
    [self.tableView setNeedsDisplay];


}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
    // This is a defensive move
    // There are cases where the nib containing the NSTableView can be loaded before the data is populated
    // by ensuring the count value is 0 and checking to see if the namesArray is not nil, the app
    // is protecting itself agains that situation
    NSInteger count=0;
    if (self.tableDataSource)
        count=[self.tableDataSource count];
    return count;
}


- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {

    // Get an existing cell with the MyView identifier if it exists
    NSTextField *result = [tableView makeViewWithIdentifier:@"LeftPaneCell" owner:self];

    // There is no existing cell to reuse so create a new one
    if (result == nil) {

        // Create the new NSTextField with a frame of the {0,0} with the width of the table.
        // Note that the height of the frame is not really relevant, because the row height will modify the height.
        NSTextField *textField;

        textField = [[NSTextField alloc] initWithFrame:NSMakeRect(2, 456, 125, 20)];
        [textField setStringValue:@"My Label"];
        [textField setBezeled:NO];
        [textField setDrawsBackground:NO];
        [textField setEditable:NO];
        [textField setSelectable:NO];
        [self.view addSubview:textField];

        // The identifier of the NSTextField instance is set to MyView.
        // This allows the cell to be reused.
        result.identifier = @"LeftPaneCell";
    }

    // result is now guaranteed to be valid, either as a reused cell
    // or as a new cell, so set the stringValue of the cell to the
    // nameArray value at row
    result.stringValue = [self.tableDataSource objectAtIndex:row];

    // Return the result
    return result;

}


@end

在LeftPaneViewController.xib中,我钩住TableView数据源并委托(delegate)给“文件的所有者”(当然是LeftPaneViewController的)。并将tableView引用出口挂钩到LeftPaneViewController.h中的tableView。我检查了这些至少一千遍;-)

然后,当我运行时,我得到以下崩溃日志:
* thread #1: tid = 0x23427, 0x00007fff82893250 libobjc.A.dylib`objc_msgSend + 16, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x00007fff82893250 libobjc.A.dylib`objc_msgSend + 16
    frame #1: 0x00007fff88f8d972 AppKit`-[NSTableRowData _addViewToRowView:atColumn:row:] + 324
    frame #2: 0x00007fff88f8d63f AppKit`-[NSTableRowData _addViewsToRowView:atRow:] + 151
    frame #3: 0x00007fff88f8bbd5 AppKit`-[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 415
    frame #4: 0x00007fff88f8b95a AppKit`-[NSTableRowData _addRowViewForVisibleRow:withPriorRowIndex:inDictionary:withRowAnimation:] + 272
    frame #5: 0x00007fff88f8ac29 AppKit`-[NSTableRowData _unsafeUpdateVisibleRowEntries] + 740
    frame #6: 0x00007fff88f8a7c1 AppKit`-[NSTableRowData updateVisibleRowViews] + 119
    frame #7: 0x00007fff88f625a7 AppKit`-[NSTableView layout] + 165
    frame #8: 0x00007fff88f15e65 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 112
    frame #9: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
    frame #10: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
    frame #11: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
    frame #12: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
    frame #13: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
    frame #14: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
    frame #15: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
    frame #16: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
    frame #17: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
    frame #18: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
    frame #19: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
    frame #20: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
    frame #21: 0x00007fff88f15cfe AppKit`-[NSView layoutSubtreeIfNeeded] + 615
    frame #22: 0x00007fff88f114ac AppKit`-[NSWindow(NSConstraintBasedLayout) layoutIfNeeded] + 201
    frame #23: 0x00007fff88e0b0a8 AppKit`_handleWindowNeedsDisplayOrLayoutOrUpdateConstraints + 446
    frame #24: 0x00007fff893d6901 AppKit`__83-[NSWindow _postWindowNeedsDisplayOrLayoutOrUpdateConstraintsUnlessPostingDisabled]_block_invoke_01208 + 46
    frame #25: 0x00007fff8d0e9417 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    frame #26: 0x00007fff8d0e9381 CoreFoundation`__CFRunLoopDoObservers + 369
    frame #27: 0x00007fff8d0c47b8 CoreFoundation`__CFRunLoopRun + 728
    frame #28: 0x00007fff8d0c40e2 CoreFoundation`CFRunLoopRunSpecific + 290
    frame #29: 0x00007fff8c17aeb4 HIToolbox`RunCurrentEventLoopInMode + 209
    frame #30: 0x00007fff8c17ab94 HIToolbox`ReceiveNextEventCommon + 166
    frame #31: 0x00007fff8c17aae3 HIToolbox`BlockUntilNextEventMatchingListInMode + 62
    frame #32: 0x00007fff88e08533 AppKit`_DPSNextEvent + 685
    frame #33: 0x00007fff88e07df2 AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
    frame #34: 0x00007fff88dff1a3 AppKit`-[NSApplication run] + 517
    frame #35: 0x00007fff88da3bd6 AppKit`NSApplicationMain + 869
    frame #36: 0x0000000100001872 TableView_In_SplitView`main(argc=3, argv=0x00007fff5fbff7e8) + 34 at main.m:13
    frame #37: 0x00007fff84d4d7e1 libdyld.dylib`start + 1

通过断点,我确定在LeftPaneViewController.m中,调用了numberOfRowsInTableView并返回2,但未调用viewForTableColumn。

TableView是基于单元格的,因此我希望可以调用viewForTableColumn。

如果我在MainMenu.xib的SplitView中简单地添加一个NSTableView并将相同的代码传输到AppDelegate.h / .m中,它就可以正常工作(当然也可以更改钩子(Hook))。也就是说,它不会崩溃,并且numberOfRowsInTableView和viewForTableColumn都被调用。

那么,我该怎么做导致崩溃?

最佳答案

好的,找到答案了。由于AppDelegate.m中的LeftPaneViewController变量(lpvc)是本地变量,因此它将在replaceSubview调用之后释放。因此,在AppDelegate.h中将其添加为(非原子的,保留)可修复崩溃。打开“僵尸”以找到答案;-)。

10-06 09:14