在 swift 函数中传递多个闭包并执行过滤
Passing multiple closures in swift function and perform filtering
在我的代码中,我有一个协议函数搜索。我想传递多个可以执行过滤过程的闭包。
有几件事让我感到困惑。
首先,如何将通用的闭包数组发送到搜索函数中。其次,我将如何遍历每个闭包来执行每个数组元素的过滤过程。
我有一个功能
func search(query: String, mainDataList:[T], ____ closuersArray, completionHandler: @escaping ([T]?, Error?) -> Void)
{
let queue = DispatchQueue(label: "SomeQueue", attributes: .concurrent)
queue.asyncAfter(deadline: .now() + 0.3, execute: {
var dataList : [T] = []
// Perform filtering
for clouser in closuersArray {
// Do something here.
}
DispatchQueue.main.async {
completionHandler(dataList, nil)
}
})
}
作为闭包的几个随机函数定义为
func containsDataClosuer(query: String, model: T) -> Bool {
// Do something here
return false
}
func someOtherClouser(query: String, model: T) -> Bool {
// Do something here
return false
}
可能的解决方案:
初始基地:
protocol Searchable {
var titleField: String { get }
var subtitleField: String { get }
var additionalField: String { get }
}
struct Item: CustomStringConvertible {
var title: String
var subtitle: String
var additional: String
var description: String {
return "<Item>: T: \(title) - S: \(subtitle) - A: \(additional)"
}
}
extension Item: Searchable {
var titleField: String { title }
var subtitleField: String { subtitle }
var additionalField: String { additional }
}
let initialList: [Item] = [Item(title: "First Title", subtitle: "First Subtitle", additional: "First Add"),
Item(title: "Second Title", subtitle: "Second Subtitle", additional: "Second Add pp"),
Item(title: "Third Title", subtitle: "Third Subtitle", additional: "Third Add"),
Item(title: "Fourth Title", subtitle: "Fourth Subtitle", additional: "Fourth Add")]
搜索参数,带有函数(因为你似乎想要 func
),或 closures
(而不是你写的 clouser
,但它们并不是真正的闭包在你的情况下)
var closureTitle: ((String, Searchable) -> Bool)
closureTitle = { searchText, aSearchable in
return aSearchable.titleField.contains(searchText)
}
var closureSubtitle: ((String, Searchable) -> Bool)
closureSubtitle = { searchText, aSearchable in
return aSearchable.subtitleField.contains(searchText)
}
func functionAdditional(_ searchText: String, _ aSearchable: Searchable) -> Bool {
return aSearchable.additionalField.contains(searchText)
}
您的主要搜索功能:
func search<T: Searchable>(query: String, mainDataList:[T], filters: [((String, T) -> Bool)], completionHandler: @escaping ([T], Error?) -> Void)
{
let queue = DispatchQueue(label: "SomeQueue", attributes: .concurrent)
queue.asyncAfter(deadline: .now() + 0.3, execute: {
//The logic:
// We do a clasic `filter` call on mainDataList
// For each item inside it, we check if at least one of the filters allows it
// If yes, we keep it (return true), else, we discard it (return false)
// That's a OR logic: If you find the search text query in ANY of three properties
// If you want an AND (meaning, text has to be present in EACH property to be valid), change the `contains` with
`filters.allSatisfy { aFilter in aFilter(query, aSearchable) }` which should do the trick
let filteredList = mainDataList.filter { aSearchable in
let keepElement = filters.contains { aFilter in
aFilter(query, aSearchable) == true
}
return keepElement
}
DispatchQueue.main.async {
completionHandler(filteredList, nil)
}
})
}
正在使用:
//With only closures
search(query: "o", mainDataList: initialList, filters: [closureTitle, closureSubtitle]) { filteredList, error in
print("Only closures: \(filteredList)")
}
//With closures and functions
search(query: "pp", mainDataList: initialList, filters: [closureTitle, closureSubtitle, functionAdditional]) { filteredList, error in
print("Closures & Functions: \(filteredList)")
}
输出:
$>Only closures: [<Item>: T: Second Title - S: Second Subtitle - A: Second Add pp, <Item>: T: Fourth Title - S: Fourth Subtitle - A: Fourth Add]
$>Closures & Functions: [<Item>: T: Second Title - S: Second Subtitle - A: Second Add pp]
在我的代码中,我有一个协议函数搜索。我想传递多个可以执行过滤过程的闭包。
有几件事让我感到困惑。 首先,如何将通用的闭包数组发送到搜索函数中。其次,我将如何遍历每个闭包来执行每个数组元素的过滤过程。
我有一个功能
func search(query: String, mainDataList:[T], ____ closuersArray, completionHandler: @escaping ([T]?, Error?) -> Void)
{
let queue = DispatchQueue(label: "SomeQueue", attributes: .concurrent)
queue.asyncAfter(deadline: .now() + 0.3, execute: {
var dataList : [T] = []
// Perform filtering
for clouser in closuersArray {
// Do something here.
}
DispatchQueue.main.async {
completionHandler(dataList, nil)
}
})
}
作为闭包的几个随机函数定义为
func containsDataClosuer(query: String, model: T) -> Bool {
// Do something here
return false
}
func someOtherClouser(query: String, model: T) -> Bool {
// Do something here
return false
}
可能的解决方案:
初始基地:
protocol Searchable {
var titleField: String { get }
var subtitleField: String { get }
var additionalField: String { get }
}
struct Item: CustomStringConvertible {
var title: String
var subtitle: String
var additional: String
var description: String {
return "<Item>: T: \(title) - S: \(subtitle) - A: \(additional)"
}
}
extension Item: Searchable {
var titleField: String { title }
var subtitleField: String { subtitle }
var additionalField: String { additional }
}
let initialList: [Item] = [Item(title: "First Title", subtitle: "First Subtitle", additional: "First Add"),
Item(title: "Second Title", subtitle: "Second Subtitle", additional: "Second Add pp"),
Item(title: "Third Title", subtitle: "Third Subtitle", additional: "Third Add"),
Item(title: "Fourth Title", subtitle: "Fourth Subtitle", additional: "Fourth Add")]
搜索参数,带有函数(因为你似乎想要 func
),或 closures
(而不是你写的 clouser
,但它们并不是真正的闭包在你的情况下)
var closureTitle: ((String, Searchable) -> Bool)
closureTitle = { searchText, aSearchable in
return aSearchable.titleField.contains(searchText)
}
var closureSubtitle: ((String, Searchable) -> Bool)
closureSubtitle = { searchText, aSearchable in
return aSearchable.subtitleField.contains(searchText)
}
func functionAdditional(_ searchText: String, _ aSearchable: Searchable) -> Bool {
return aSearchable.additionalField.contains(searchText)
}
您的主要搜索功能:
func search<T: Searchable>(query: String, mainDataList:[T], filters: [((String, T) -> Bool)], completionHandler: @escaping ([T], Error?) -> Void)
{
let queue = DispatchQueue(label: "SomeQueue", attributes: .concurrent)
queue.asyncAfter(deadline: .now() + 0.3, execute: {
//The logic:
// We do a clasic `filter` call on mainDataList
// For each item inside it, we check if at least one of the filters allows it
// If yes, we keep it (return true), else, we discard it (return false)
// That's a OR logic: If you find the search text query in ANY of three properties
// If you want an AND (meaning, text has to be present in EACH property to be valid), change the `contains` with
`filters.allSatisfy { aFilter in aFilter(query, aSearchable) }` which should do the trick
let filteredList = mainDataList.filter { aSearchable in
let keepElement = filters.contains { aFilter in
aFilter(query, aSearchable) == true
}
return keepElement
}
DispatchQueue.main.async {
completionHandler(filteredList, nil)
}
})
}
正在使用:
//With only closures
search(query: "o", mainDataList: initialList, filters: [closureTitle, closureSubtitle]) { filteredList, error in
print("Only closures: \(filteredList)")
}
//With closures and functions
search(query: "pp", mainDataList: initialList, filters: [closureTitle, closureSubtitle, functionAdditional]) { filteredList, error in
print("Closures & Functions: \(filteredList)")
}
输出:
$>Only closures: [<Item>: T: Second Title - S: Second Subtitle - A: Second Add pp, <Item>: T: Fourth Title - S: Fourth Subtitle - A: Fourth Add]
$>Closures & Functions: [<Item>: T: Second Title - S: Second Subtitle - A: Second Add pp]