我正在Swift 5.1中开发macOS Cocoa应用程序。在主窗口中,我有两个完全相同的NSOutlineViews,它们具有完全相同的内容。我想启用一个同步模式,如果项目在两个NSOutlineViews之一中展开/折叠,则相应的项目在另一个NSOutlineViews中同时展开/折叠。我试图通过在委托中实现shouldExpandItem和shouldCollapseItem来做到这一点。对于两个NSOutlineViews,该委托是同一对象,并且我具有引用两个NSOutlineViews的插座,以区分两者。问题是,如果我在shouldExpandItem中以编程方式调用expandItem,则会再次为另一个NSOutlineView调用该方法,从而导致无限循环和堆栈溢出。我发现了一个肮脏的解决方案,该解决方案可以通过将相关NSOutlineView的代表暂时设置为nil,展开/折叠该项目,然后再重新设置代表来工作。代码如下:
func outlineView(_ outlineView: NSOutlineView,shouldExpandItem item: Any) -> Bool {
let filePath = (item as! FileSystemObject).fullPath
let trueItem = item as! FileSystemObject
trueItem.children = Array()
do {
let contents = try FileManager.default.contentsofDirectory(atPath: filePath!)
for (_,item) in contents.enumerated() {
let entry = FileSystemObject.init()
entry.fullPath = URL.init(fileURLWithPath: filePath!).appendingPathComponent(item).path
if entry.exists {
trueItem.children.append(entry)
}
}
} catch {
}
if outlineView == self.leftOutlineView {
self.rightOutlineView.delegate = nil;
self.rightOutlineView.expandItem(item)
self.rightOutlineView.delegate = self;
} else {
self.leftOutlineView.delegate = nil;
self.leftOutlineView.expandItem(item)
self.leftOutlineView.delegate = self;
}
return true
}
func outlineView(_ outlineView: NSOutlineView,shouldCollapseItem item: Any) -> Bool {
if outlineView == self.leftOutlineView {
self.rightOutlineView.delegate = nil;
self.rightOutlineView.collapseItem(item)
self.rightOutlineView.delegate = self;
} else {
self.leftOutlineView.delegate = nil;
self.leftOutlineView.collapseItem(item)
self.leftOutlineView.delegate = self;
}
return true
}
这似乎可行,但是我担心这种方法可能会出问题。是暂时设置委托人以取消可能的解决方案,还是我应该注意任何警告?您是否可以建议另一种模式来实现这一目标?谢谢
编辑:根据以下评论和答案
由于收到了答复/评论,我找到了最简单的解决方案。 代替在outlineViewShouldExpand / Collapse方法中实现同步逻辑,可以实现outlineViewDidExpand和outlineViewDidCollapse并将同步逻辑放在那里。以编程方式扩展/折叠项目时不会调用后一种方法,因此没有无限循环或堆栈溢出的风险。
代码如下:
func outlineViewItemDidExpand(_ notification: Notification) {
let outlineView = notification.object as! NSOutlineView
let userInfo = notification.userInfo as! Dictionary<String,Any>
let item = userInfo["NSObject"]
if outlineView == self.leftOutlineView {
self.rightOutlineView.animator().expandItem(item)
} else {
self.leftOutlineView.animator().expandItem(item)
}
}
func outlineViewItemDidCollapse(_ notification: Notification) {
let outlineView = notification.object as! NSOutlineView
let userInfo = notification.userInfo as! Dictionary<String,Any>
let item = userInfo["NSObject"]
if outlineView == self.leftOutlineView {
self.rightOutlineView.animator().collapseItem(item)
} else {
self.leftOutlineView.animator().collapseItem(item)
}
}
此外,现在,我无法理解为什么动画的展开/折叠是动画的,这与我的原始方法不兼容。 我希望这对某人有帮助,对我很有帮助。非常感谢。