See if the following example helps. You can create a playground in Xcode, then you can copy and paste the code into the playground, which will allow you to play around with the code in a less complex setting than iOS.
Note that the candy category provides a way to divide all the candies into a small number of groups for display in the segmented control. In fact, that category property was specifically added to the struct for that purpose. How do you propose to divide your items into three groups? A username is unique, so you can’t make groups of people with the same username, and a post is probably unique, so that doesn’t provide a way to group your items. You can’t display all the usernames in the segmented control, nor can you display all the posts. What do you envision being displayed in the segmented control? Are you going to add a category property to your items for the purpose of grouping your items, e.g. with values like Sports, News, and General based on the posts? Or, maybe a category property based on the usernames like US, Europe, Far East?
//: Playground - noun: a place where people can play
import UIKit
struct Post {
var username = ""
var text = ""
}
class MyViewController {
var filteredPosts: [Post] = []
let posts = [
Post(username:"andy", text:"Nutter Bar"),
Post(username:"joe", text:"Chocolate Bar"),
Post(username:"jderbs", text:"Chocolate Chip"),
Post(username:"kate", text:"Dark Chocolate"),
Post(username:"joe", text:"Lollipop"),
Post(username:"jderbs", text:"Candy Cane"),
Post(username:"jderbs", text:"Jaw Breaker"),
Post(username:"Kate", text:"Not on my watch."),
Post(username:"jderbs", text:"It's night time."),
Post(username:"zed", text:"Gold Token"),
]
func searchBarIsEmpty() -> Bool {
return false
}
//Segmented control: All, a-i, j-r, s-z
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
let usernameCategories = [
"All": "a"..."z",
"a-i": "a"..."i",
"j-r": "j"..."r",
"s-z": "s"..."z"
]
let usernameCategory = usernameCategories[scope]! //Note the bang! If you pass anything other than the four legal keys in the dictionary=> error: found nil when unwrapping optional
filteredPosts = posts.filter() { (post : Post) -> Bool in
var doesCategoryMatch = false
let username = post.username
if let firstLetterChar = username.first {
let firstLetterStr = String(describing: firstLetterChar)
doesCategoryMatch = usernameCategory.contains(firstLetterStr)
}
if searchBarIsEmpty() {
return doesCategoryMatch
} else {
return doesCategoryMatch && post.text.lowercased().contains(searchText.lowercased())
}
}
}
}
let viewController = MyViewController()
viewController.filterContentForSearchText("n")
for post in viewController.filteredPosts {
print(post.username)
print(post.text)
print("--")
}
print("\n--new search--\n")
viewController.filterContentForSearchText("n", scope:"a-i")
for post in viewController.filteredPosts {
print(post.username)
print(post.text)
print("--")
}
print("\n--new search--\n")
viewController.filterContentForSearchText("n", scope:"j-r")
for post in viewController.filteredPosts {
print(post.username)
print(post.text)
print("--")
}
Output:
andy
Nutter Bar
--
jderbs
Candy Cane
--
jderbs
It's night time.
--
zed
Gold Token
--
--new search--
andy
Nutter Bar
--
--new search--
jderbs
Candy Cane
--
jderbs
It's night time.
--
Note that when the last argument to a function, e.g. filter(), is an anonymous function, you can move the anonymous function outside of the argument list:
filter(...) {
}
Here’s a simple example:
func go(x: Int, dostuff: (Int) -> String) -> Void {
let result = dostuff(x)
print(result)
}
go(x: 3) { y in
return "Hello \(y)"
}
--output:--
Hello 3
I left at least one mistake/improvement for you to find in the big example.