I'm receiving the error "Extra trailing closure passed in call" on the authViewModel.fetchUser() function. From what I've gathered researching online this means that fetchuser can't have the trailing closure (the brackets), I am confused about what in my fetchuser function says that it cannot have the {} after the call. Or maybe I'm not understanding the error at all. Thank you in advance!
FeedCellViewModel
import Foundation
class FeedCellViewModel: ObservableObject {
@Published var posts = [Post]()
let service = PostService()
let authViewModel = AuthViewModel()
init() {
fetchPosts()
}
func fetchPosts() {
service.fetchPosts { posts in
self.posts = posts
for i in 0 ..< posts.count {
let uid = posts[i].uid
self.authViewModel.fetchUser() { user in
self.posts[i].user = user
}
}
}
}
}
AuthViewModel
import SwiftUI
import FirebaseAuth
import FirebaseCore
import FirebaseStorage
import FirebaseFirestore
import FirebaseFirestoreSwift
class AuthViewModel: NSObject, ObservableObject {
@Published var userSession: FirebaseAuth.User?
@Published var currentUser: User?
@Published var selectedImage: UIImage?
@Published var didAuthenticateUser = false
private var tempUserSession: FirebaseAuth.User?
private let service = UserService()
static let shared = AuthViewModel()
override init() {
super.init()
userSession = Auth.auth().currentUser
fetchUser()
}
func login(withEmail email: String, password: String) {
Auth.auth().signIn(withEmail: email, password: password) { result, error in
if let error = error {
print("DEBUG: Failed to sign in with error \(error.localizedDescription)")
return
}
self.userSession = result?.user
self.fetchUser()
}
}
func register(withEmail email: String, password: String, fullname: String) {
Auth.auth().createUser(withEmail: email, password: password) { result, error in
if let error = error {
print("DEBUG: Failed to register with error \(error.localizedDescription)")
return
}
guard let user = result?.user else { return }
self.tempUserSession = user
let data = ["email": email,
"fullname": fullname,
"uid": user.uid]
COLLECTION_USERS
.document(user.uid)
.setData(data) { _ in
self.didAuthenticateUser = true
}
self.uploadProfileImage(self.selectedImage)
self.fetchUser()
}
}
func signOut() {
// sets user session to nil so we show login view
self.userSession = nil
// signs user out on server
try? Auth.auth().signOut()
}
func uploadProfileImage(_ image: UIImage?) {
guard let uid = tempUserSession?.uid else { return }
ImageUploader.uploadImage(image: image) { profileImageUrl in
Firestore.firestore().collection("users")
.document(uid)
.updateData(["profileImageUrl": profileImageUrl]) { _ in
self.userSession = self.tempUserSession
}
}
}
func fetchUser() {
guard let uid = userSession?.uid else { return }
COLLECTION_USERS.document(uid).getDocument { snapshot, _ in
guard let user = try? snapshot?.data(as: User.self) else { return }
self.currentUser = user
}
}
}
CodePudding user response:
You're seeing this error because your fetchUser()
function doesn't take a closure parameter (or any parameters for that matter).
A trailing closure is just a nicer way of passing a closure as a parameter, given it's the last parameter to a method. Try running this example in a playground to get a feel for this:
func hello(closure: () -> Void) {
print("calling closure")
closure()
print("finished")
}
// these are the same
hello(closure: { print("hello!!") })
hello { print("hello!!") }
If you want to provide the user in a closure to the caller, return the user as a parameter to the closure in addition to setting the currentUser
.
func fetchUser(finishedFetching: @escaping (User) -> Void) {
guard let uid = userSession?.uid else { return }
COLLECTION_USERS.document(uid).getDocument { snapshot, _ in
guard let user = try? snapshot?.data(as: User.self) else { return }
self.currentUser = user
finishedFetching(user)
}
}
Read more about closures in the Swift language guide.
They are essentially unnamed functions that you can store and pass around.
You'll learn there why I marked the our closure as @escaping
.