Custom Firebase Data Service Class : Swift 3

匿名 (未验证) 提交于 2019-12-03 07:36:14

问题:

I'm searching for a clean way to retrieve (and sometimes save) data from Firebase in Swift. It's annoying me that all my database calls are written in the middle of the view controller code. So I'm looking for some kind of custom data service class. I found this tutorial that's close to what I want: http://www.mobilecyberpunks.com/?p=82.

They promised a Part II but I cannot find this second part, so I guess this was never made. In this second part they promised to cover retrieving and saving data with this custom data service (which is the most important part of the whole thing for me).

I'm thinking of an API class (like in the tutorial) and when I'm retrieving data, and it finishes retrieving from firebase, I save it in a data set in this api class. Then I will posting a notification with Notification Center. But I'm am not sure whether this is best practice or a good way to do this.

Has anyone an idea how to do this (finishing this tutorial I found or in another way)?

Thanks in advance!

回答1:

Making a custom Class for the communicating is generally a good idea if you need extensive function's and make numerous calls to your server.

The two preferred methods for this are:-

  • Protocol-Delegate Method

  • _completionBlocks:

Below answer contains both.

Custom Class

import Foundation import Firebase  @objc protocol FIRShowAlertDelegate {     func showFIRAlert(_ message : String)     @objc optional func activityIndic()     } class FIRController :{    var delegate  : FIRShowAlertDelegate!    func loginUser(_ emailAddress : String!, password : String , completionBlock : @escaping ((currentUserID : String!) -> Void)){      FIRAuth.auth()?.signIn(withEmail: emailAddress, password: password,                                      completion: {(user,err) in                                          if err != nil{                                              self.delegate.showFIRAlert("Error logging you in,\(err?.localizedDescription)")                                               }else{                                              completionBlock(user!.uid)                                          }                          })         }  func retrieveUserData(_ currentId : String!, completionBlock : @escaping ((_ userName : String?) -> Void)){   FIRDatabase.database().reference().child("Users").child(currentId).observeSingleEvent(of: .value, with: {(userSnap) in          if userSnap.exists(){              if let userDict = userSnap.value! as? [String:AnyObject]{                  completionBlock(userDict["username"] as! String             }         }else{              completionBlock(nil, nil)             print("No such user exists: \(currentId)")         }     })  }   }  

Your ViewController

class AnyViewController : UIViewController, FIRShowAlertDelegate{      let firebaseControllerHandle  : FIRController = FIRController()      override func viewDidLoad() {      super.viewDidLoad()           firebaseControllerHandle.delegate = self          firebaseControllerHandle.loginUser("abc@xyz.com", password: "123454321", completionBlock: { (userID) in              print("user : \(userID), logged in")         })                 }      func showFIRAlert(_ message : String){         let alertController : UIAlertController = UIAlertController(title: "MyApp", message: message, preferredStyle: .alert)        let okAction : UIAlertAction = UIAlertAction(title: "Ok", style: .default) { (alert) in            print("User pressed ok function")           }        alertController.addAction(okAction)        alertController.popoverPresentationController?.sourceView = view        alertController.popoverPresentationController?.sourceRect = view.frame        self.present(alertController, animated: true, completion: nil)      }      func activityIndic() {        // Use for showing the activity indicator while the data is being retrieved      }     } 


回答2:

I started to use this solution and polished it a little bit, and I came to a pretty handy solution.

I created a custom class named FirebaseAPI. This is a singleton class. This class contains all the methods for Firebase (Authentication, Database, Storage, ...).

Example:

FirebaseAPI.swift

import FirebaseAuth import FirebaseDatabase   class FirebaseAPI {     static let shared = FirebaseAPI()      private init() {}      //Authentication     func logInUser(onCompletion: @escaping (String?) -> Void {         FIRAuth.auth().signInAnonymously(completion: {(user, error) in              if error == nil {                 onCompletion(user!.uid)             } else {                 onCompletion(nil)             }         })     }      //Database     func getObjects(parameter: ParamaterClass, onCompletion: @escaping ([ObjectClass]) -> Void) {         Constants.Firebase.References.Object?.observe(.value, with: { snapshot in             var objects = [ObjectClass]()              if snapshot.exists() {                 for child in snapshot.children.allObjects {                     let object = Object(snapshot: child as! FIRDataSnapshot)                     objects.append(object)                 }             }             onCompletion(objects)         })     } } 

Constants.swift

import FirebaseDatabase   struct Constants {     struct Firebase {         static var CurrentUser: FIRDatabaseReference?         static var Objects: FIRDatabaseReference?     } } 

AppDelegate.swift

import UIKit import Firebase   @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {     var window: UIWindow?      func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {         FIRApp.configure()          FirebaseAPI.shared.logInUser(onCompletion { uid in              if uid != nil {                 Constants.Firebase.References.CurrentUser = FIRDatabase.database().reference().child("users").child(uid!)                 Constants.Firebase.References.CurrentUser.keepSynced(true)                 Constants.Firebase.References.Objects = FIRDatabase.database().reference().child("objects")                Constants.Firebase.Reference.Objects?.keepSynced(true)             }         })     }     return true } 

I can give you a example of calling methods in the FirebaseAPI in a ViewController, but an example of such a method is given in the code of the AppDelegate.swift up here (the FirebaseAPI.shared.logInUser method).

Used this structure in 3 different projects up till now and it works fluently!



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!