簡體   English   中英

為什么在將數據上傳到Firebase時我的應用程序凍結?

[英]Why does my app freeze while I upload data to firebase?

更新: ****很少編輯,我發現實際上唯一凍結的是從firebase中檢索數據,尤其是需要檢索的圖像。 func initOberserver用於從firebase檢索數據。 因此,需要每次在后台執行此操作。 但tableview必須在此期間可用?****

我在后台線程方面有些掙扎。 我正在制作一個Firebase應用程序,但是當我將某些內容上傳到Firebase並將其取回該應用程序時,我的應用程序凍結了一段時間。

我在一個單獨的打開文件中有2個常量:

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

我有一個viewcontroller:ListVC可以使用此功能從firebase檢索數據。

func initObservers() {

    //LoadingOverlay.shared.showOverlay(self.view)
    dispatch_async(backgroundQueue, {
        DataService.ds.REF_LISTS.observeEventType(.Value, withBlock: { snapshot in
            print(snapshot.value)

            self.lists = []

            if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {

                for snap in snapshots {
                    print("SNAP: \(snap)")

                    if let listDict = snap.value as? Dictionary<String, AnyObject> {
                        let key = snap.key
                        let list = List(listKey: key, dictionary: listDict)
                        self.lists.insert(list, atIndex:0)
                    }
                }
            }

            //LoadingOverlay.shared.hideOverlayView()
            self.tableView.reloadData()

        })

    })

}

然后我有一個視圖控制器addVC,它使用以下功能將數據發布到Firebase:

@IBAction func postListItem(sender: AnyObject) {

        if let addTitle = addTitle.text where addTitle != "", let addDescription = addDescription.text where addDescription != "", let addLocation = addLocation.text where addLocation != "" {

            dispatch_async(backgroundQueue, {
                self.postToFirebase(nil)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                    let storyboard = UIStoryboard(name: "Main", bundle: nil)
                    let listVC = storyboard.instantiateViewControllerWithIdentifier("TBC") as! UITabBarController
                    listVC.selectedIndex = 1
                    self.presentViewController(listVC, animated: false, completion: nil)
                })
            })
        }
    }

func postToFirebase(imgUrl: String?) {

        LoadingOverlay.shared.showOverlay(self.overlayView)

        var post: Dictionary<String, AnyObject> = ["username": currentUsername, "description": addDescription.text!, "title": addTitle.text!, "location": addLocation.text!, "images": self.base64String]

        let firebasePost = DataService.ds.REF_LISTS.childByAutoId()
        firebasePost.setValue(post)

    }

如您所見,我嘗試了在Internet和Stack Overflow上找到的代碼和說明來進行嘗試。 但是,即使我打開應用程序並轉到listVC,它也會在2秒鍾后凍結大約10秒鍾,並且當我發布內容時,轉到listVC時也會凍結一段時間。

我也有這段代碼:

let uploadImage = image
        let imageData = UIImageJPEGRepresentation(uploadImage, 0.5)
        self.base64String = imageData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)

沒有此代碼,它不會凍結,並且在幾秒鍾內完成“這就是事情”。 但我需要此代碼將圖像發布到Firebase嗎?

讓我們簡化一下-這是概念性的,但可能會有所幫助。

首先,填充tableView數據源。 有一種更好的方法來初始填充dataSource並重新加載tableView,因此假設在此示例中您只有一個小的數據集。

self.lists = []

DataService.ds.REF_LISTS.observeEventType(.ChildAdded, withBlock: { snapshot in
  self.lists.insert(snapshot.value, atIndex:0)
  self.tableView.reloadData //this is for example only
}

稍后,例如在您的IBAction中,將一些數據寫入Firebase

var post: Dictionary<String, AnyObject> = ["username": currentUsername, "description": addDescription.text!, "title": addTitle.text!, "location": addLocation.text!, "images": self.base64String]

let firebasePost = DataService.ds.REF_LISTS.childByAutoId()
firebasePost.setValue(post)

從此以后,只要將Firebase數據寫入觀察到的節點,您的應用程序就會收到有關該新數據的通知,並將其添加到dataSource和tableView更新中。

如果您需要首先加載一個表格視圖,然后在之后監視.childAdded事件,那么這是一種技術。

var lastNamesArray = [String]()
var initialLoad = true

//add observers so we load the current lastNames and are aware of any
// lastName additions

peopleRef.observeEventType(.ChildAdded, withBlock: { snapshot in

  let lastName = snapshot.value["last_name"] as? String      
  self.lastNamesArray.append(lastName)

  //upon first load, don't reload the tableView until all children are loaded
  if ( self.initialLoad == false ) {
    self.lastNamesTableView.reloadData()
  }
})

//this .Value event will fire AFTER the child added events to reload the tableView 
//  the first time and to set subsequent childAdded events to load after each
//  child is added in the future

peopleRef.observeSingleEventOfType(.Value, withBlock: { snapshot in

    print("inital data loaded so reload tableView!  /(snapshot.childrenCount)")
    self.lastNamesTableView.reloadData()
    self.initialLoad = false        
})

在您的最后一個函數postToFirebase ,您在后台線程下執行了一個UI操作,看來這是您的錯誤。

LoadingOverlay.shared.showOverlay(self.overlayView)

正如在問題下方的注釋中所寫,在名為initObservers的第一個函數結尾處, reloadData()發生了同樣的事情。

強烈建議不要從后台線程(例如,計時器,通信等)更新UI控件等。 這可能是導致崩潰的原因,有時很難識別。 而是使用它們來強制在UI線程(始終是“主”線程)上執行代碼。

dispatch_async(dispatch_get_main_queue()) {
    // this code will be running on the main thread
}

更新 :關於您對UIImageJPEGRepresentation的最后一個問題,這是一個如何啟動它的示例:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
    let getImage =  UIImage(data: NSData(contentsOfURL: NSURL(string: self.remoteImage)))
    UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)

    dispatch_async(dispatch_get_main_queue()) {
        self.image?.image = getImage
        return
    }
}

迅捷3

DispatchQueue.global(attributes: .qosBackground).async {
    print("This is run on the background queue")

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM