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

如何针对[Any]类型数组实现TableView选中单元格的元素增删判断?

嘿,这个场景我太熟了!因为[Any]类型的数组里元素没有统一的Equatable协议支持,直接用contains()肯定行不通,不过有几个比for-in循环优雅得多的解决方案,咱们一个个来看:

方案1:给自定义对象实现Equatable + 泛型判断

首先,让你的两个自定义对象都实现Equatable协议(根据对象的唯一属性来定义相等规则),然后写一个泛型方法来帮你判断元素是否存在:

// 先给自定义对象实现Equatable
class CustomA: Equatable {
    let id: Int
    init(id: Int) {
        self.id = id
    }
    
    static func == (lhs: CustomA, rhs: CustomA) -> Bool {
        // 用唯一标识判断相等,比如这里的id
        return lhs.id == rhs.id
    }
}

class CustomB: Equatable {
    let name: String
    init(name: String) {
        self.name = name
    }
    
    static func == (lhs: CustomB, rhs: CustomB) -> Bool {
        return lhs.name == rhs.name
    }
}

// 自定义泛型判断方法
func elementExists<T: Equatable>(_ element: T, in array: [Any]) -> Bool {
    return array.contains { item in
        // 先尝试把数组元素转成目标类型,再判断相等
        guard let typedItem = item as? T else { return false }
        return typedItem == element
    }
}

// 使用示例
var mixedArray: [Any] = [CustomA(id: 5), CustomB(name: "3")]
let targetElement = CustomA(id: 5)

if elementExists(targetElement, in: mixedArray) {
    // 移除对应元素
    mixedArray.removeAll { item in
        guard let item = item as? CustomA else { return false }
        return item == targetElement
    }
} else {
    mixedArray.append(targetElement)
}

这个方法既保证了类型安全,又复用了Equatable的相等判断逻辑,比手动for-in循环清爽多了。

方案2:用协议统一唯一标识(无需Equatable)

如果不想给对象实现Equatable,可以定义一个协议让所有自定义对象都提供唯一标识,通过标识来判断元素是否存在:

// 定义一个获取唯一标识的协议
protocol Identifiable {
    var uniqueIdentifier: String { get }
}

// 让自定义对象遵守协议
extension CustomA: Identifiable {
    var uniqueIdentifier: String {
        return "\(id)" // 用id作为唯一标识
    }
}

extension CustomB: Identifiable {
    var uniqueIdentifier: String {
        return name // 用name作为唯一标识(确保name唯一)
    }
}

// 判断方法
func elementWithIdExists(_ targetId: String, in array: [Any]) -> Bool {
    return array.contains { item in
        guard let identifiableItem = item as? Identifiable else { return false }
        return identifiableItem.uniqueIdentifier == targetId
    }
}

// 使用示例
let targetId = targetElement.uniqueIdentifier
if elementWithIdExists(targetId, in: mixedArray) {
    mixedArray.removeAll { item in
        guard let identifiableItem = item as? Identifiable else { return false }
        return identifiableItem.uniqueIdentifier == targetId
    }
} else {
    mixedArray.append(targetElement)
}

这个方案灵活性更高,适合那些不方便实现Equatable的场景。

方案3:用枚举包装类型(最推荐)

其实最优雅的方式是尽量避免使用[Any],如果数组里只有这两种自定义对象,用枚举来包装它们,这样数组类型就变成了具体的枚举类型,还能轻松实现Equatable:

// 定义枚举包装两种自定义对象
enum CustomElement: Equatable {
    case typeA(CustomA)
    case typeB(CustomB)
    
    // 自定义相等判断逻辑
    static func == (lhs: CustomElement, rhs: CustomElement) -> Bool {
        switch (lhs, rhs) {
        case (.typeA(let a1), .typeA(let a2)):
            return a1.id == a2.id
        case (.typeB(let b1), .typeB(let b2)):
            return b1.name == b2.name
        default:
            // 不同类型的元素肯定不相等
            return false
        }
    }
}

// 数组改成枚举类型,再也不用[Any]了!
var elementArray: [CustomElement] = [.typeA(CustomA(id:5)), .typeB(CustomB(name:"3"))]

// 直接用原生的contains()和removeAll()!
let target = CustomElement.typeA(CustomA(id:5))
if elementArray.contains(target) {
    elementArray.removeAll { $0 == target }
} else {
    elementArray.append(target)
}

这个方案彻底解决了[Any]带来的类型不安全问题,代码更清晰、健壮,是我最推荐的做法。


内容的提问来源于stack exchange,提问作者user9413278

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:59:58