【问题标题】:Custom Firebase Data Service Class : Swift 3自定义 Firebase 数据服务类:Swift 3
【发布时间】:2017-02-27 09:20:39
【问题描述】:

我正在寻找一种干净的方式来在 Swift 中从 Firebase 检索(有时是保存)数据。我所有的数据库调用都写在视图控制器代码的中间,这让我很恼火。所以我正在寻找某种自定义数据服务类。我发现本教程与我想要的很接近:http://www.mobilecyberpunks.com/?p=82

他们承诺了第二部分,但我找不到第二部分,所以我猜这从未制作过。在第二部分中,他们承诺使用此自定义数据服务检索和保存数据(这对我来说是整个事情中最重要的部分)。

我正在考虑一个 API 类(如教程中所示),当我检索数据并完成从 firebase 检索时,我将其保存在此 api 类的数据集中。然后我将在通知中心发布通知。但我不确定这是否是最佳做法或这样做的好方法。

有谁知道如何做到这一点(完成我找到的本教程或以其他方式)?

提前致谢!

【问题讨论】:

  • 确实很有趣的问题,期待答案。一个有趣的后续问题是实现后端服务独立性的策略,以便您可以在应用程序中使用自定义后端 API,并且可以将其配置为使用 Firebase、Parse、Backendless 或任何其他服务。
  • 看来你没看错,你到底在找什么?如何在 firebase 类与您的 viewControllers 之间进行通信?
  • @Dravidian 是的,这是正确的。我正在寻找一种在 Firebase 类与我的 ViewController 之间进行通信的方法,但要摆脱 Firebase 方法的所有回调。将这些方法包装在一个单独的类中。该类包含例如一个方法 getUsers() -> [User] 或只是 getUsers (虽然第一个是首选)。
  • @xpereta 我为此制定了一个方便的结构(问题的第一部分:自定义数据服务类)。有关代码,请参阅我发布的已接受答案。对于您的后续问题:非常有趣,但目前为 Parse 配置此功能将毫无用处,因为 Parse 将于 2017 年 1 月关闭。我没有尝试过其他服务,因为 Firebase 拥有我需要的一切到目前为止。但如果它遇到我的工作,并且我开发了这样的结构,我会让你(和其他所有人)在这个页面上发布!

标签: ios swift firebase firebase-realtime-database firebase-authentication


【解决方案1】:

如果您需要广泛的功能并对您的服务器进行大量调用,则为通信创建一个自定义类通常是一个好主意。

两种首选方法是:-

  • Protocol-Delegate方法

  • _completionBlocks:

以下答案包含两者。

自定义类

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)")
        }
    })
 }


} 

你的视图控制器

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
     }
    }

【讨论】:

  • 谢谢!这正是我想要的!我使用了完成块,所以我的 ViewController 中仍然有完成块,但代码更少。 ViewController中原本回调的所有代码都移到了这里
  • 抱歉,按 Enter 太快了。所以最初回调中的所有代码都移到了我的自定义类 FirebaseAPI 中。谢谢!
【解决方案2】:

我开始使用这个解决方案并稍微改进了一下,我得出了一个非常方便的解决方案。

我创建了一个名为 FirebaseAPI 的自定义类。这是一个单例类。此类包含 Firebase 的所有方法(身份验证、数据库、存储...)。

例子:

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
}

我可以给你一个在 ViewController 中调用 FirebaseAPI 方法的例子,但是在 AppDelegate.swift 的代码中给出了这种方法的例子(FirebaseAPI.shared.logInUser 方法)。

到目前为止,在 3 个不同的项目中都使用了这种结构,并且运行流畅!

【讨论】:

  • 虽然你的代码没问题,但我记得在 iOS 应用程序开发(游戏和企业应用程序)方面非常有经验的 CTO(老板)告诉我,我不应该让我的 AppDelegate 类臃肿。无论如何,您使用的是 Firebase 的 Observe 而不是 SingleObserve,而且您似乎没有移除观察者。我一直在为连接到 Firebase 的应用程序使用自定义类/API 服务,但仅用于 SingleObserveEvent。我正在发布一个关于此的问题,您可能想回答或感兴趣。
  • 嘿,你能解释一下你为什么用单例模式写它吗?
  • 如果与 AppDelegate 存在差异,您能否分享您如何在 VC 中使用它(例如,您可能不想拥有 VC 的所有对象?@Charlotte1993
猜你喜欢
  • 1970-01-01
  • 2017-08-11
  • 2012-07-13
  • 1970-01-01
  • 2017-11-17
  • 2018-01-05
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多