ios - 我想在视图控制器之间快速传递一个用户对象类型的实例
问题描述
我有一个用户对象,我从 firebase 获取它的值,我想基本上在我所有的其他视图控制器中传递这个对象。我正在使用情节提要,我查找了如何执行此操作,我发现我可以覆盖 prepare 方法,但我没有成功,因为我不知道如何调用该方法,或者如果它曾经被调用过,它只是没用。然后我发现你可以将一个 vc 分配给另一个视图控制器并像这样传递数据,但我遇到了一个问题:
在 HomeViewController 中,我有这个从 firebase 获取数据并将其分配给用户的方法:
extension HomeViewController {
public func AssignValueToUserObject() {
guard let uid = Auth.auth().currentUser?.uid else {
print("Could not get user id")
return
}
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { [self] snapshot in
if let dictionary = snapshot.value as? [String: AnyObject] {
user.first_name = dictionary["first_name"] as? String
user.last_name = dictionary["last_name"] as? String
user.email = dictionary["email"] as? String
user.profile_picture = dictionary["profile_picture"] as? String
}
}, withCancel: nil)
} // End AssignValueToUserObject Method
} // End extension
这就是我在 HomeViewController 中将该用户对象复制到我的 ProfileViewController 中的内容:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
title = "Home"
checkIfUserIsLoggedIn()
copyData()
}
func checkIfUserIsLoggedIn() {
// Check if user is logged in
if Auth.auth().currentUser == nil {
// User is not logged in, send user to login screen
let loginVC = storyboard?.instantiateViewController(identifier: "login")
loginVC?.modalPresentationStyle = .fullScreen
present(loginVC!, animated: false)
}
// User is logged in, fetch their info
AssignValueToUserObject()
} // End checkIfUserIsLoggedIn method
// Copy user from Home to Profile
func copyData() {
let vc = storyboard?.instantiateViewController(identifier: "profile") as? ProfileViewController
vc?.user = user
}
调试后,我发现了一个大问题,即在 AssignValueToUserObject 方法中将值分配给用户之前调用了复制方法,这对我来说绝对没有意义。
我在复制方法之前调用了assign方法,那它是如何工作的?经过一番研究,我发现它与完成处理有关,但我就是不明白。
解决方案
如评论中所述,使用异步函数,您不能立即期望返回值。处理此问题的一种常见方法是使用回调函数或完成处理程序。
我包括一个非常基本的例子。请注意,我现在没有进行任何错误处理——您希望将其构建得更健壮,但这至少得到了这个概念:
extension HomeViewController {
public func assignValueToUserObject(completion: @escaping () -> Void) { //completion handler gets passed as an parameter
guard let uid = Auth.auth().currentUser?.uid else {
print("Could not get user id")
return
}
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { [self] snapshot in
if let dictionary = snapshot.value as? [String: AnyObject] {
user.first_name = dictionary["first_name"] as? String
user.last_name = dictionary["last_name"] as? String
user.email = dictionary["email"] as? String
user.profile_picture = dictionary["profile_picture"] as? String
completion() //call once the action is done
}
}, withCancel: nil)
} // End AssignValueToUserObject Method
} // End extension
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
title = "Home"
checkIfUserIsLoggedIn()
//don't call copy here anymore
}
func checkIfUserIsLoggedIn() {
// Check if user is logged in
if Auth.auth().currentUser == nil {
// User is not logged in, send user to login screen
let loginVC = storyboard?.instantiateViewController(identifier: "login")
loginVC?.modalPresentationStyle = .fullScreen
present(loginVC!, animated: false)
}
// User is logged in, fetch their info
assignValueToUserObject(completion: {
self.copyData() //only copy once the completion handler is run
})
} // End checkIfUserIsLoggedIn method
更新,展示了一种使用单例来监控不同视图控制器中的用户值的方法:
import Combine
struct User {
var id : UUID //whatever properties your user model has
}
class UserManager {
@Published var user : User?
static public var shared = UserManager()
private init() {
}
func login() {
//do your firebase call here and set `user` when done in the completion handler
self.user = User(id: UUID())
}
}
class HomeViewController : UIViewController {
private var userManager = UserManager.shared
private var cancellable : AnyCancellable?
init() {
super.init(nibName: nil, bundle: nil)
setupUserLink() //make sure this gets called in whatever initializer is used
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUserLink() //make sure this gets called in whatever initializer is used
}
func setupUserLink() {
cancellable = userManager.$user.compactMap { $0 }.sink { user in
print(user.id.uuidString) //do something with the user value -- assign it to a variable, a control, etc
}
}
}
class ProfileViewController : UIViewController {
//do the same pattern as in HomeViewController, setting up the user link to be monitored
}
推荐阅读
- ios - Swift静态值停留在原始值
- postgresql - 使用 liquibase 更改索引名称
- glm - 关于解释多元 GLM 的结果的问题
- swift - RealityKit 中的双目相机
- python - 多个基于不同的数据框
- autodesk-bim360 - Forge/Bim360 中是否有任何 API 方法用于按文本内容(全文搜索)过滤(pdf)文档/文件?
- c# - Azure 分析服务 Rest API 错误 - 状态 400(错误请求)和“未经授权”消息
- ruby-on-rails - Ruby如何用布尔值获取数组?
- android-studio - 我的嵌套片段的实现有什么问题?
- javascript - 在 Docusaurus v2 中将外部 javascript 添加到文档页面