Reputation: 111
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
}
}
}
Upvotes: 2
Views: 12843
Reputation: 7668
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 our closure as @escaping
.
Upvotes: 5