想使用数据模型按用户姓氏进行索引 table 视图排序,但无法理解如何
Wanna do indexed table view sorting by user's surname using data model, but cannot understand how
我是新手,所以这个问题可能很愚蠢。
我制作了一些带有用户名的索引 table 视图。现在我添加了一个带有用户姓氏的标签,我想使用数据模型使我的索引 table 视图按用户姓氏排序,但我真的不知道该怎么做。
这可能会有所帮助,因此 here 您可以立即查看我的应用程序的运行情况。
首先,有 FriendsSearchViewController
所有用户模板。
import UIKit
final class FriendsSearchViewController: UITableViewController {
var friends = [
"Polina",
"Ivan",
"Pavel",
"Maria",
"Nick"
]
var userFriends: [String] = []
var friendSectionTitles = [String]()
var friendsDictionary = [String: [String]]()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(
nibName: "FriendCell",
bundle: nil),
forCellReuseIdentifier: "friendCell")
for friend in friends {
let friendKey = String(friend.prefix(1))
if var friendValues = friendsDictionary[friendKey] {
friendValues.append(friend)
friendsDictionary[friendKey] = friendValues
} else {
friendsDictionary[friendKey] = [friend]
}
}
friendSectionTitles = [String](friendsDictionary.keys)
friendSectionTitles = friendSectionTitles.sorted(by: { [=11=] < })
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
friendSectionTitles.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let friendKey = friendSectionTitles[section]
if let friendValues = friendsDictionary[friendKey] {
return friendValues.count
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
friendSectionTitles[section]
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
friendSectionTitles
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard
let cell = tableView.dequeueReusableCell(withIdentifier: "friendCell", for: indexPath) as? FriendCell
else { return UITableViewCell() }
var currentFriend = friends[indexPath.row]
let friendKey = friendSectionTitles[indexPath.section]
if let friendValues = friendsDictionary[friendKey] {
currentFriend = friendValues[indexPath.row]
}
cell.configure(
photo: UIImage(named: "\(indexPath.row)") ?? UIImage(),
name: currentFriend,
surname: "")
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
defer {
tableView.deselectRow(at: indexPath, animated: true)
}
let friendKey = friendSectionTitles[indexPath.section]
var currentFriend = ""
if let friendValues = friendsDictionary[friendKey] {
currentFriend = friendValues[indexPath.row]
}
if userFriends.firstIndex(of: currentFriend) == nil {
userFriends.append(currentFriend)
}
self.performSegue(withIdentifier: "addFriend", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addFriend",
let myFriendsViewController = segue.destination as? MyFriendsViewController {
myFriendsViewController.friends = userFriends
}
}
}
并且有 MyFriendsViewController
的用户已添加到好友列表:
import UIKit
final class MyFriendsViewController: UITableViewController {
var friends = [String]() {
didSet {
//
}
}
@IBAction func addFriend(segue: UIStoryboardSegue) {
guard segue.identifier == "addFriend",
let allFriendsViewController = segue.source as? FriendsSearchViewController
else { return }
friends = allFriendsViewController.userFriends
tableView.reloadData()
}
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(
nibName: "FriendCell",
bundle: nil),
forCellReuseIdentifier: "friendCell")
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
friends.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard
let cell = tableView.dequeueReusableCell(withIdentifier: "friendCell", for: indexPath) as? FriendCell
else { return UITableViewCell() }
let currentFriend = friends[indexPath.row]
cell.configure(
photo: UIImage(named: "\(indexPath.row)") ?? UIImage(),
name: currentFriend,
surname: "")
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
defer { tableView.deselectRow(
at: indexPath,
animated: true)}
performSegue(
withIdentifier: "showProfile",
sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addFriend",
let allFriendsViewController = segue.destination as? FriendsSearchViewController {
allFriendsViewController.userFriends = friends
}
}
}
还有 UserModel
可能看起来不正确:
import UIKit
struct UserModel {
let userName: String
let userSurname: String
let userPhoto: UIImage
let userAge: String
}
和 FriendCell
单元格配置:
import UIKit
class FriendCell: UITableViewCell {
@IBOutlet var friendPhoto: AvatarImage!
@IBOutlet var friendName: UILabel!
@IBOutlet var friendSurname: UILabel!
func configure(
photo: UIImage,
name: String,
surname: String) {
self.friendPhoto.image = photo
self.friendName.text = name
self.friendSurname.text = surname
}
}
我无法想象我该怎么办。我应该怎么做?拜托,你能给我一些代码示例的想法吗?谢谢!
1.
对 UserModel
进行一些小的调整
// Make UserModel conform to Equatable protocol so you can
// compare two UserModel Objects using == or firstIndexOf
// Read more on Equatable here: https://developer.apple.com/documentation/swift/equatable
struct UserModel: Equatable {
// I changed this to userFirstName to be more clear
let userFirstName: String
let userSurname: String
// I made UIImage? optional, but you can change if you wish
let userPhoto: UIImage?
let userAge: Int
}
2.
将结构添加到数组而不是 FriendsSearchViewController
中的字符串
// Update friends array to hold structs of people
var friends = [
UserModel(userFirstName: "Polina",
userSurname: "James",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Ivan",
userSurname: "Gomez",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Pavel",
userSurname: "Harvey",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Maria",
userSurname: "Fernando",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Nick",
userSurname: "Cage",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Shawn",
userSurname: "Frank",
userPhoto: UIImage(systemName: "star"),
userAge: 20)
]
3.
将这些更改为结构数组,而不是 FriendsSearchViewController
中的字符串
// userFriends should now be an array of UserModel type, not String
var userFriends: [UserModel] = []
var friendSectionTitles = [String]()
// Also friendsDictionary should be an array of UserModel type, not String
var friendsDictionary = [String: [UserModel]]()
4.
调整 viewDidLoad
中的循环以使用结构,因为它们在 FriendsSearchViewController
中不再是字符串
// Now friend will be of type UserModel, not string
for friend in friends {
// So we need to check the prefix of the UserMode.userSurname
let friendKey = String(friend.userSurname.prefix(1))
if var friendValues = friendsDictionary[friendKey] {
friendValues.append(friend)
friendsDictionary[friendKey] = friendValues
} else {
friendsDictionary[friendKey] = [friend]
}
}
friendSectionTitles = [String](friendsDictionary.keys)
friendSectionTitles = friendSectionTitles.sorted(by: { [=13=] < })
5.
调整 tableView 数据源函数以使用结构而不是字符串
在两个 ViewControllers
中修复此行 cellForRowAt
// Now you need to get the UserModel.userFirstName and UserModel.userSurname
cell.textLabel?.text = "\(currentFriend.userFirstName) \(currentFriend.userSurname)"
在 FriendsSearchViewController
中修复 didSelectRowAt
中的这一行
// This should not be a string
var currentFriend = friends[indexPath.row]
6.
在 MyFriendsViewController
中将朋友数组从字符串更改为 UserModel
var friends = [UserModel]() {
didSet {
//
}
}
7.
现在要按姓氏对朋友列表进行排序,请调整退出 segue 函数以对朋友数组进行排序
@IBAction func addFriend(segue: UIStoryboardSegue) {
guard segue.identifier == "addFriend",
let allFriendsViewController = segue.source as? FriendsSearchViewController
else { return }
// Sort data when you come back
friends = allFriendsViewController.userFriends.sorted {
[=17=].userSurname < .userSurname
}
tableView.reloadData()
}
这应该会给你想要的结果
但是,请阅读这些主题以充分掌握这些概念:
Sorting arrays
最后的建议是将您的问题分解成更小的部分,同时解决堆栈溢出问题。
例如这里有几个不同的主题,例如如何创建模型、如何将结构与数组一起使用、如何对数组进行排序。
每个问题有一个主题将帮助您更快地得到答案,但您尝试做事并提出问题是件好事。
我是新手,所以这个问题可能很愚蠢。
我制作了一些带有用户名的索引 table 视图。现在我添加了一个带有用户姓氏的标签,我想使用数据模型使我的索引 table 视图按用户姓氏排序,但我真的不知道该怎么做。
这可能会有所帮助,因此 here 您可以立即查看我的应用程序的运行情况。
首先,有 FriendsSearchViewController
所有用户模板。
import UIKit
final class FriendsSearchViewController: UITableViewController {
var friends = [
"Polina",
"Ivan",
"Pavel",
"Maria",
"Nick"
]
var userFriends: [String] = []
var friendSectionTitles = [String]()
var friendsDictionary = [String: [String]]()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(
nibName: "FriendCell",
bundle: nil),
forCellReuseIdentifier: "friendCell")
for friend in friends {
let friendKey = String(friend.prefix(1))
if var friendValues = friendsDictionary[friendKey] {
friendValues.append(friend)
friendsDictionary[friendKey] = friendValues
} else {
friendsDictionary[friendKey] = [friend]
}
}
friendSectionTitles = [String](friendsDictionary.keys)
friendSectionTitles = friendSectionTitles.sorted(by: { [=11=] < })
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
friendSectionTitles.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let friendKey = friendSectionTitles[section]
if let friendValues = friendsDictionary[friendKey] {
return friendValues.count
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
friendSectionTitles[section]
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
friendSectionTitles
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard
let cell = tableView.dequeueReusableCell(withIdentifier: "friendCell", for: indexPath) as? FriendCell
else { return UITableViewCell() }
var currentFriend = friends[indexPath.row]
let friendKey = friendSectionTitles[indexPath.section]
if let friendValues = friendsDictionary[friendKey] {
currentFriend = friendValues[indexPath.row]
}
cell.configure(
photo: UIImage(named: "\(indexPath.row)") ?? UIImage(),
name: currentFriend,
surname: "")
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
defer {
tableView.deselectRow(at: indexPath, animated: true)
}
let friendKey = friendSectionTitles[indexPath.section]
var currentFriend = ""
if let friendValues = friendsDictionary[friendKey] {
currentFriend = friendValues[indexPath.row]
}
if userFriends.firstIndex(of: currentFriend) == nil {
userFriends.append(currentFriend)
}
self.performSegue(withIdentifier: "addFriend", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addFriend",
let myFriendsViewController = segue.destination as? MyFriendsViewController {
myFriendsViewController.friends = userFriends
}
}
}
并且有 MyFriendsViewController
的用户已添加到好友列表:
import UIKit
final class MyFriendsViewController: UITableViewController {
var friends = [String]() {
didSet {
//
}
}
@IBAction func addFriend(segue: UIStoryboardSegue) {
guard segue.identifier == "addFriend",
let allFriendsViewController = segue.source as? FriendsSearchViewController
else { return }
friends = allFriendsViewController.userFriends
tableView.reloadData()
}
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(
nibName: "FriendCell",
bundle: nil),
forCellReuseIdentifier: "friendCell")
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
friends.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard
let cell = tableView.dequeueReusableCell(withIdentifier: "friendCell", for: indexPath) as? FriendCell
else { return UITableViewCell() }
let currentFriend = friends[indexPath.row]
cell.configure(
photo: UIImage(named: "\(indexPath.row)") ?? UIImage(),
name: currentFriend,
surname: "")
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
defer { tableView.deselectRow(
at: indexPath,
animated: true)}
performSegue(
withIdentifier: "showProfile",
sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addFriend",
let allFriendsViewController = segue.destination as? FriendsSearchViewController {
allFriendsViewController.userFriends = friends
}
}
}
还有 UserModel
可能看起来不正确:
import UIKit
struct UserModel {
let userName: String
let userSurname: String
let userPhoto: UIImage
let userAge: String
}
和 FriendCell
单元格配置:
import UIKit
class FriendCell: UITableViewCell {
@IBOutlet var friendPhoto: AvatarImage!
@IBOutlet var friendName: UILabel!
@IBOutlet var friendSurname: UILabel!
func configure(
photo: UIImage,
name: String,
surname: String) {
self.friendPhoto.image = photo
self.friendName.text = name
self.friendSurname.text = surname
}
}
我无法想象我该怎么办。我应该怎么做?拜托,你能给我一些代码示例的想法吗?谢谢!
1.
对 UserModel
// Make UserModel conform to Equatable protocol so you can
// compare two UserModel Objects using == or firstIndexOf
// Read more on Equatable here: https://developer.apple.com/documentation/swift/equatable
struct UserModel: Equatable {
// I changed this to userFirstName to be more clear
let userFirstName: String
let userSurname: String
// I made UIImage? optional, but you can change if you wish
let userPhoto: UIImage?
let userAge: Int
}
2.
将结构添加到数组而不是 FriendsSearchViewController
// Update friends array to hold structs of people
var friends = [
UserModel(userFirstName: "Polina",
userSurname: "James",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Ivan",
userSurname: "Gomez",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Pavel",
userSurname: "Harvey",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Maria",
userSurname: "Fernando",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Nick",
userSurname: "Cage",
userPhoto: UIImage(systemName: "star"),
userAge: 20),
UserModel(userFirstName: "Shawn",
userSurname: "Frank",
userPhoto: UIImage(systemName: "star"),
userAge: 20)
]
3.
将这些更改为结构数组,而不是 FriendsSearchViewController
// userFriends should now be an array of UserModel type, not String
var userFriends: [UserModel] = []
var friendSectionTitles = [String]()
// Also friendsDictionary should be an array of UserModel type, not String
var friendsDictionary = [String: [UserModel]]()
4.
调整 viewDidLoad
中的循环以使用结构,因为它们在 FriendsSearchViewController
// Now friend will be of type UserModel, not string
for friend in friends {
// So we need to check the prefix of the UserMode.userSurname
let friendKey = String(friend.userSurname.prefix(1))
if var friendValues = friendsDictionary[friendKey] {
friendValues.append(friend)
friendsDictionary[friendKey] = friendValues
} else {
friendsDictionary[friendKey] = [friend]
}
}
friendSectionTitles = [String](friendsDictionary.keys)
friendSectionTitles = friendSectionTitles.sorted(by: { [=13=] < })
5. 调整 tableView 数据源函数以使用结构而不是字符串
在两个 ViewControllers
中修复此行cellForRowAt
// Now you need to get the UserModel.userFirstName and UserModel.userSurname
cell.textLabel?.text = "\(currentFriend.userFirstName) \(currentFriend.userSurname)"
在 FriendsSearchViewController
didSelectRowAt
中的这一行
// This should not be a string
var currentFriend = friends[indexPath.row]
6.
在 MyFriendsViewController
var friends = [UserModel]() {
didSet {
//
}
}
7. 现在要按姓氏对朋友列表进行排序,请调整退出 segue 函数以对朋友数组进行排序
@IBAction func addFriend(segue: UIStoryboardSegue) {
guard segue.identifier == "addFriend",
let allFriendsViewController = segue.source as? FriendsSearchViewController
else { return }
// Sort data when you come back
friends = allFriendsViewController.userFriends.sorted {
[=17=].userSurname < .userSurname
}
tableView.reloadData()
}
这应该会给你想要的结果
但是,请阅读这些主题以充分掌握这些概念:
Sorting arrays
最后的建议是将您的问题分解成更小的部分,同时解决堆栈溢出问题。
例如这里有几个不同的主题,例如如何创建模型、如何将结构与数组一起使用、如何对数组进行排序。
每个问题有一个主题将帮助您更快地得到答案,但您尝试做事并提出问题是件好事。