自定义Dropdown数据传递/获取异常,无需static实现多实例
问题根源分析
你的核心问题是实例不匹配:
- 你在
ViewController中创建的countryDropDown实例,和showDropdown方法里通过storyboard实例化的VC是两个完全独立的对象。你调用addItems给前者的数组添加数据,但popover显示的是后者的空数组。 btOK的IBAction属于storyboard实例化的对象,它的pop变量没有被正确关联到当前显示的popover,所以调用close()无效;用static时所有实例共享同一个popover,所以能关闭,但这破坏了多实例的独立性。
解决方案
1. 修正customDropdown类代码
移除showDropdown中重新实例化控制器的逻辑,直接用当前实例作为popover的内容控制器,确保每个实例拥有独立的popover和数据:
class customDropdown: NSViewController { @IBOutlet weak var cvDropDown: NSCollectionView! // 每个实例拥有自己的popover,不需要static private var pop: NSPopover! var dropDownLabelText = [String]() var dropDownToggle = [Int]() var selectedItemsIndex: [Int] { dropDownToggle.enumerated() .filter { $0.element == 1 } .map { $0.offset } } // 初始化时创建popover override func viewDidLoad() { super.viewDidLoad() pop = NSPopover() pop.behavior = .transient pop.contentViewController = self } // 实现你调用的removeAll方法 func removeAll() { dropDownLabelText.removeAll() dropDownToggle.removeAll() cvDropDown.reloadData() } // 实现addItems方法 func addItems(labelText: String, toggleState: Int) { dropDownLabelText.append(labelText) dropDownToggle.append(toggleState) cvDropDown.reloadData() } func showDropdown(_ sender: NSButton) { // 直接使用当前实例的popover,不需要重新从storyboard加载 pop.show(relativeTo: sender.bounds, of: sender, preferredEdge: .minY) } @IBAction func btOK(_ sender: Any) { pop.close() // 可以在这里添加选中数据的回调通知,比如用闭包 } }
2. 修正ViewController中的调用逻辑
确保你操作的是同一个实例,不要引用ViewController.countryDropDown(这是类属性,你应该用实例属性):
// 作为ViewController的实例属性,而不是类属性 let countryDropDown = customDropdown() let personDropDown = customDropdown() @IBAction func btMultiCountry(_ sender: Any) { countryDropDown.removeAll() for c in g.country { countryDropDown.addItems(labelText: c.countryName!, toggleState: 1) } countryDropDown.showDropdown(sender as! NSButton) }
3. 关键补充:闭包回调获取选中数据
为了在ViewController中获取每个下拉实例的选中结果,可以给customDropdown添加一个闭包属性,在点击OK时触发:
class customDropdown: NSViewController { // 添加回调闭包 var onSelectionConfirmed: (([Int]) -> Void)? @IBAction func btOK(_ sender: Any) { pop.close() // 传递选中的索引 onSelectionConfirmed?(selectedItemsIndex) } }
在ViewController中使用时:
@IBAction func btMultiCountry(_ sender: Any) { countryDropDown.removeAll() for c in g.country { countryDropDown.addItems(labelText: c.countryName!, toggleState: 1) } // 设置回调 countryDropDown.onSelectionConfirmed = { selectedIndices in print("选中的国家索引:\(selectedIndices)") // 这里处理选中数据 } countryDropDown.showDropdown(sender as! NSButton) }
额外注意事项
- 确保storyboard中的
customDropdown控制器的class属性正确设置为customDropdown,且cvDropDown和btOK的IBAction绑定正确。 - 不要通过storyboard重复实例化
customDropdown,所有实例都通过代码创建(let countryDropDown = customDropdown()),确保数据和popover属于同一个实例。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

