我们在Swift开发过程中经常会碰到数组去重的情况,基本数据类型数组的去重比较好办,那如果碰到model模型类的数组去重,又怎么进行科学合理的处理呢?通常对model进行去重,要依赖其某个属性,一般是一个唯一ID,然后通过该ID来进行判断是否有重复的模型。
比如有个模型AModel如下:
class AModel {
var name: String?
var img: String?
var aID: Int = 0 //唯一ID
}
普通处理
AModel的属性中有可以用来判断唯一性的aID,因此我们在对装着AModel类型的数组[AModel]进行去重时可以这么处理:
func handleFilterArray(arr:[AModel]) -> [AModel] {
var temp = [AModel]() //存放符合条件的model
var idxArr = [Int]() //存放符合条件model的aID,用来判断是否重复
for model in arr {
let index = model.aID //遍历获得model的唯一标识aID
if !idxArr.contains(index){ //如果该aID已经添加过,则不再添加
idxArr.append(index)
temp.append(model) //如果该aID没有添加过,则添加到temp数组中
}
}
return temp //最终返回的数组中已经筛选掉重复aID的model
}
泛型处理
如果我们需要处理不同model类型的数组,那我们是否可以将上面的方法写成一个通用的方法,比如下面这样用Swift的泛型来处理:
//T为不同model的类型
func handleFilterArray(arr:[T]) -> [T] {
//具体实现
}
可是我们碰到一个问题,你用泛型来写的话,这个泛型无法确定你不同模型中需要判断的那个ID是什么,因为BModel的唯一ID是bID,CModel的唯一ID是cID,因此我们怎么才能把这个不同的标识符给带到这个函数中来呢,下面先来看方法一,利用protocol来处理:
protocol arrayFilterable {
var identifer:Int {get} //该只读属性用来获取不同model的不同唯一ID
}
extension AModel: arrayFilterable{
var identifer: Int{
return aID //AModel则返回aID
}
}
extension BModel: arrayFilterable{
var identifer: Int{
return bID //BModel则返回bID
}
}
然后我们的处理方法就可以写成这样:
func handleFilterArray<T:arrayFilterable>(arr:[T]) -> [T] {
var temp = [T]()
var idxArr = [Int]()
for model in arr {
let index = model.identifer //通过identifer来判断不同模型是否有重复数据
if !idxArr.contains(index){
idxArr.append(index)
temp.append(model)
}
}
return temp
}
更合理的泛型处理
但以上的方法是不是还是显得有点不那么高效,毕竟需要每个模型都遵循arrayFilterable协议,而且显得可扩展性一般,如果有一个DModel用来判断唯一性的不是ID,而是一个字符串呢,我们再来看看方法二,利用泛型结合Swift数组的高阶函数map来处理:
//直接给Array扩展一个方法
extension Array {
//该函数的参数filterCall是一个带返回值的闭包,传入模型T,返回一个E类型
func handleFilter<E: Equatable>(_ filterCall: (T) -> E) -> [T] {
var temp = [T]()
for model in self {
//调用filterCall,获得需要用来判断的属性E
let identifer = filterCall(model)
//此处利用map函数 来将model类型数组转换成E类型的数组,以此来判断
identifer 是否已经存在,如不存在则将model添加进temp
if !temp.map( { filterCall($0) } ).contains(identifer) {
temp.append(model)
}
}
return temp
}
}
上面传入闭包filterCall的返回值E,就是模型的属性中用来判断唯一型的那个属性,需要遵循Equatable,才能使用数组的contains函数来判断是否已经存在。
如果AModel用来判断唯一性的不是aID,而是name属性,则一个装着有好多重复AModel的数组AModelArray可以这么调用这个函数:
let filterArray = AModelArray.handleFilter( { $0.name } )
$0.name即filterCall闭包的返回值,用来判断数组中model唯一性的依据。
结语
通过这个小应用,可以看出Swift中强大的泛型特性能够让我们根据不同的需求,来编写灵活强大的函数和类型,让我们避免重复冗余的代码,更加快速高效的达到应用目的。