Swift开发:Firebase管理器类是否应使用静态成员?探讨编程设计
嘿,我看你正在打造一个集成Firebase多功能的项目,还想到用统一管理器来简化重复操作,这个思路超棒!把分散在各个视图控制器里的Firebase操作封装起来,确实能大幅减少冗余代码,提升项目的可维护性。
下面是完善后的Firebase管理器实现方案,结合单例模式和模块化封装,帮你搞定认证、数据库、存储的统一操作:
Firebase 统一管理器实现
import Foundation import Firebase class FirebaseManager { // 全局唯一实例,单例模式核心 static let shared = FirebaseManager() // 实时获取当前登录用户UID,无需手动维护 var currentUID: String? { return Auth.auth().currentUser?.uid } // Firebase核心服务引用,初始化后全局可用 let databaseRootRef: DatabaseReference let storageRootRef: StorageReference let authentication: Auth // 私有初始化,确保只能通过shared获取实例 private init() { // 初始化Firebase核心(如果没在AppDelegate/SceneDelegate做过的话) FirebaseApp.configure() self.authentication = Auth.auth() self.databaseRootRef = Database.database().reference() self.storageRootRef = Storage.storage().reference() } // MARK: - 认证模块 /// 邮箱密码登录 func signIn(withEmail email: String, password: String, completion: @escaping (Result<User, Error>) -> Void) { authentication.signIn(withEmail: email, password: password) { authResult, error in if let error = error { completion(.failure(error)) return } guard let user = authResult?.user else { completion(.failure(NSError(domain: "FirebaseManager", code: -1, userInfo: [NSLocalizedDescriptionKey: "用户信息获取失败"]))) return } completion(.success(user)) } } /// 邮箱密码注册 func signUp(withEmail email: String, password: String, completion: @escaping (Result<User, Error>) -> Void) { authentication.createUser(withEmail: email, password: password) { authResult, error in if let error = error { completion(.failure(error)) return } guard let user = authResult?.user else { completion(.failure(NSError(domain: "FirebaseManager", code: -1, userInfo: [NSLocalizedDescriptionKey: "用户信息获取失败"]))) return } completion(.success(user)) } } // MARK: - 数据库模块 /// 向指定路径上传数据 func uploadData(to path: String, data: [String: Any], completion: @escaping (Error?) -> Void) { databaseRootRef.child(path).setValue(data) { error, _ in completion(error) } } /// 从指定路径获取单条数据 func downloadData(from path: String, completion: @escaping (Result<[String: Any], Error>) -> Void) { databaseRootRef.child(path).observeSingleEvent(of: .value) { snapshot in guard let data = snapshot.value as? [String: Any] else { completion(.failure(NSError(domain: "FirebaseManager", code: -2, userInfo: [NSLocalizedDescriptionKey: "数据格式不匹配"]))) return } completion(.success(data)) } withCancel: { error in completion(.failure(error)) } } // MARK: - 存储模块 /// 上传本地文件到Firebase Storage func uploadFile(to path: String, fileURL: URL, completion: @escaping (Result<URL, Error>) -> Void) { let targetRef = storageRootRef.child(path) let uploadTask = targetRef.putFile(from: fileURL) uploadTask.observe(.success) { _ in targetRef.downloadURL { url, error in if let error = error { completion(.failure(error)) return } guard let downloadURL = url else { completion(.failure(NSError(domain: "FirebaseManager", code: -3, userInfo: [NSLocalizedDescriptionKey: "下载链接获取失败"]))) return } completion(.success(downloadURL)) } } uploadTask.observe(.failure) { snapshot in if let error = snapshot.error { completion(.failure(error)) } } } }
核心设计说明
- 单例模式:通过
static let shared创建全局唯一实例,私有初始化方法避免外部重复创建,确保Firebase服务只初始化一次。 - 自动维护用户UID:用计算属性
currentUID实时获取当前登录用户ID,不用手动存储和更新。 - 模块化封装:把认证、数据库、存储的操作拆分成独立方法,每个方法只负责一件事,回调用
Result类型让逻辑更清晰。 - 全局复用引用:初始化时就创建好数据库、存储、认证的核心引用,不用在每个视图控制器里重复创建。
使用示例
在任意视图控制器里直接调用即可,再也不用重复写Firebase初始化代码:
// 登录示例 FirebaseManager.shared.signIn(withEmail: "test@example.com", password: "123456") { result in switch result { case .success(let user): print("登录成功,用户UID:\(user.uid)") case .failure(let error): print("登录失败:\(error.localizedDescription)") } } // 上传用户数据到数据库示例 guard let uid = FirebaseManager.shared.currentUID else { return } let userData = ["nickname": "小明", "avatarURL": "xxx"] FirebaseManager.shared.uploadData(to: "users/\(uid)", data: userData) { error in if let error = error { print("数据上传失败:\(error.localizedDescription)") } else { print("数据上传成功") } }
内容的提问来源于stack exchange,提问作者Ryan Jin
相关产品推荐
相关产品推荐

