You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:40:40