如何针对[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
相关产品推荐
相关产品推荐

