Cocoa 如何使NSTableViewRow中的按钮响应所表示的对象

Cocoa 如何使NSTableViewRow中的按钮响应所表示的对象,cocoa,nstableview,cocoa-bindings,nstablecellview,Cocoa,Nstableview,Cocoa Bindings,Nstablecellview,我为这个问题奋斗了很长时间。我正在开发一个文件复制管理器模块,到目前为止,除了“取消”按钮外,我已经能够使所有功能都正常工作。出于某种原因,当我单击特定行的“取消”按钮时,按钮操作同时指向多行 在对该问题进行了几天的研究后,我成功地使用以下方法使对象取消了行所代表的操作: -(IBAction)btnCancelOperationClick:(id)sender { NSInteger row = [_tableView rowForView:sender]; if (row

我为这个问题奋斗了很长时间。我正在开发一个文件复制管理器模块,到目前为止,除了“取消”按钮外,我已经能够使所有功能都正常工作。出于某种原因,当我单击特定行的“取消”按钮时,按钮操作同时指向多行

在对该问题进行了几天的研究后,我成功地使用以下方法使对象取消了行所代表的操作:

-(IBAction)btnCancelOperationClick:(id)sender {
    NSInteger row = [_tableView rowForView:sender];
    if (row != -1) {
        FileCopyOperation *opr = [_fileCopyOperations objectAtIndex:row];
        [opr cancel];
        [_fileCopyOperations removeObjectAtIndex:row];
        [_tableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationEffectFade];
    }
}
这很好,我可以取消操作并相应地更新我的表。其他一切都按预期工作,但我的代码或绑定肯定有问题。我从nib加载此单元格,然后使用以下方法注册此nib:

[_tableView registerNib:[[NSNib alloc]initWithNibNamed:@"FileCopyCell" bundle:nil] forIdentifier:@"FileCopyCell"];
我让QueueController成为文件的所有者,并像这样钩住了所有内容:

如果有人能为我指出正确的方向,让这件事正常工作,我将不胜感激。提前谢谢

编辑以添加更多代码示例

-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    FileCopyCell *cell = [tableView makeViewWithIdentifier:@"FileCopyCell" owner:self];
    FileCopyOperation *opr = [_fileCopyOperations objectAtIndex:row];

    [cell.fileName setStringValue:[NSString stringWithFormat:@"Copying \"%@\"",opr.fName]];
    [cell.progressBar setDoubleValue:((opr.bWritten.doubleValue / opr.fSize.doubleValue) * 100)];
    [cell.totalBytes setStringValue:[NSString stringWithFormat:@"of %@",[NSByteCountFormatter stringFromByteCount:opr.fSize.longLongValue countStyle:NSByteCountFormatterCountStyleFile]]];
    [cell.status setStringValue:[NSString stringWithFormat:@"%@",[NSByteCountFormatter stringFromByteCount:opr.bWritten.longLongValue countStyle:NSByteCountFormatterCountStyleFile]]];
    [cell.icon setImage:[[NSWorkspace sharedWorkspace]iconForFile:opr.srcURL.path]];
    [cell.cancelButton setTarget:self];
    return cell;
}

-(void)windowDidLoad {
    [super windowDidLoad];
    _fileCopyOperations = [NSMutableArray new];
    windowFrame = [self.window frame];
    rows = 0;

    [_tableView registerNib:[[NSNib alloc]initWithNibNamed:@"FileCopyCell" bundle:nil] forIdentifier:@"FileCopyCell"];

    if (!fileCopyManager) {
        fileCopyManager = [FileCopyManager sharedFileCopyManager];
        [fileCopyManager.fileCopyQueue addObserver:self forKeyPath:@"operationCount" options:NSKeyValueObservingOptionNew context:(void*)fileCopyManager];
    }

    [_scrollView setHasHorizontalScroller:NO];
    [_scrollView setHasVerticalScroller:NO];
}

最好的方法是子类化
NSTableCellView
,让它处理自己的操作和表示的对象。例如,表示
Foo
实例的单元格可以有两个属性:
Foo
fooController
。调用(
nonatomic
foo
setter时,单元格可以更新自己的UI以表示传递的
foo
。当
Foo
控制器创建表单元格时,它可以实例化一个
FooCell
实例,将自身设置为
fooController
,并分配
Foo
实例,让单元格自行处理。取消按钮的目标可以是它自己的单元格,当调用
-cancel:
操作时,它可以告诉它的
fooController
做什么(因为
Foo
控制器负责更新队列和表视图),并且因为它有一个对它的
Foo
的引用,它可以通过一些
-cancelFoo:(Foo*)Foo
方法将其传递给控制器,而无需依赖控制器来查找其索引(如果您正在设置行出现和消失的动画,或者用户正在快速取消行中的一组,但它们的删除会延迟并异步更新,则索引可能不准确)


又好又干净。整洁且有组织地控制/分离责任。单元处理自己的UI更新和操作,并知道自己的foo;foo控制器处理其foo集合、表视图以及foo单元格的分配。

感谢Joshua Nozzi,根据他的建议,我将按钮操作从控制器移动到了单元格类。在cell类中,我使用下面的方法访问表示的对象并发送
[操作取消]
消息

-(IBAction)cancelOpr:(id)sender {
    NSButton *button = (NSButton*)sender;
    FileCopyOperation *opr = [(NSTableCellView*)[button superview]objectValue];
    [opr cancel];
    // This code calls the controller [removeObject:] method that takes care of cleaning everything out and updates the GUI accordingly.
    AppDelegate *ad = (AppDelegate*)[[NSApplication sharedApplication]delegate];
    QueueWindowController *qc = [ad getQueueController];
    [qc.fileCopyOperations performSelectorOnMainThread:@selector(removeObject:) withObject:opr waitUntilDone:YES];
}
你可以得到完整的项目


我不明白问题的本质。如果我理解正确的话,那就是“当我单击某一行的“取消”按钮时,按钮操作同时指向多行”。这到底是什么意思?单击时是否有多个按钮高亮显示?(你的截图看起来有点像那样。)是否多次调用了
-btnCancelOperationClick:
?用什么
发送者
?表是否与
\u fileCopyOperations
的顺序完全相同(数组和表内容之间没有插入排序)?我也感到困惑。代码摘录可以正常工作,还是没有问题?对于目标行动,它看起来很好。有了代码,一切都不正常?@Kenthomass是的,当我单击时,多个按钮会高亮显示,但是-btnCancelOperationClick:只调用一次,并按正确的操作进行操作。现在的问题是表面上的,一切正常,但当我点击某一行的取消按钮时,该按钮在其他行中高亮显示。是的,表的顺序与_fileOperations相同。@stevesliva是的,代码可以工作,但当我单击“取消”按钮时,它会取消正确的操作,但“取消”按钮也会在所有其他行上高亮显示。您的表视图委托是否尝试在
-tableView:viewForTableColumn:row:
中自定义视图,
-tableView:rowViewForRow:
,或
-tableView:didAddRowView:forRow:
?如果是,则显示该代码。
QueueController
是否实现了
-awakeFromNib
?也显示该代码。(它将被多次调用,这可能会使它出错。)同样,显示任何自定义行视图或单元格视图类的代码,尝试配置内容或点击“取消”按钮。感谢您的建议,我将以这种方式重写应用程序。正如您所说,应该包含和分离代码以避免这些问题。我认为取消按钮的混淆在于您将控制器设置为文件的所有者,它可能与单元格自己的xib中设置的文件的所有者类冲突。是的,这可能是问题所在,我发现很难访问
[FileOperation cancel]
从cellview nib。我正在运行文件操作,我希望能够取消由行表示的文件操作。用户将点击cancel按钮,这将向FileOperation发送一条消息并调用cancel方法。如果不是通过文件的所有者,我似乎找不到访问控制器的方法。我将尝试在不通过文件所有者访问QueueController的情况下使其工作。如何设置nstablecellview以处理其自身的操作,以及如何设置其表示的对象?转发类声明?你能给我举一个例子,说明你是如何做到这一点的吗?