Pan MluvĨí Pan MluvĨí - 6 months ago 42
Swift Question

App freezing when Alamofire is downloading

I wanna work with my app while data are downloading. Don't want to be bothered with loader. I am executing several alamofire GET calls. What do i need to have smooth app while doing stuff.

let headers = [ "header" : "pass"
]

var nextCheck = next

if(next > count){
let tempN = next - 1000
nextCheck = count - tempN
}

Alamofire.request(.GET, urlDomain + "_table1?offset=\(nextCheck)", headers: headers, encoding: .URL)
.responseJSON() { response in

if response.result.isSuccess {

let json = JSON(response.result.value!)
//print(json)
let done = true
var doneDownloading = false

for i in 0..<json["resource"].count {

let id_pobor = json["resource"][i]["id_bor"].stringValue
let misto = json["resource"][i]["mio"].stringValue
let nazev_oc = json["resource"][i]["naze"].stringValue
let tel = json["resource"][i]["tel"].stringValue
let ulice = json["resource"][i]["uli"].stringValue
let exp_logo = json["resource"][i]["logo"].stringValue


let count = json["meta"]["count"].intValue
let next = json["meta"]["next"].intValue

if(i == json["resource"].count - 1){
doneDownloading = true
}

completionHandler(done, id_pobor, misto, nazev_oc, gpsn, tel, ulice, exp_logo, gpse, id_obor, www, Id_prov, cinnost, psc, id_region, id_oblast, logo, provoz, eshop, count, next, doneDownloading)
}

if(json["resource"].count == 0){
completionHandler(done, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, 0, true)
}
} else {
completionHandler(false, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, 0, true)
}


this method is done several times with multiple offset pagination.

this is how i call this method. I am using REALM to store this. I am loading 40 000 + rows

private func getDataForE21Table(){
self.getReq.getE21(nextOffsetE21, count: countOffsetE21) { (done, id_pobor, misto, nazev_oc, gpsn, tel, ulice, exp_logo, gpse, id_obor, www, Id_prov, cinnost, psc, id_region, id_oblast, logo, provoz, eshop, count, next, doneDownloading) in
if(done){
self.saveToRealm.saveE21(id_pobor, misto: misto, nazev_oc: nazev_oc, gpsn: gpsn, tel: tel, ulice: ulice, exp_logo: exp_logo, gpse: gpse, id_obor: id_obor, www: www, Id_prov: Id_prov, cinnost: cinnost, psc: psc, id_oblast: id_oblast, logo: logo, provoz: provoz)
if(doneDownloading){
self.s.saveTableDates(self.s.e21Time, forKey: "e21Time")
self.nextOffsetE21 = self.nextOffsetE21 + 1000
self.countOffsetE21 = count
NSNotificationCenter.defaultCenter().postNotificationName("loadMoreDataE21", object: nil)
}
} else {
SwiftLoader.hide()
}
}
}


My class that needs to be run in background

import Foundation
import SwiftLoader
import RealmSwift

class Synchronize {

private let getReq = GetReq()
private let postReq = PostReq()
private let saveToRealm = SavaDataToRealmDatabase()
private let arrOfTables = ["e21", "e21sle", "evi22", "evi23oc", "regiony"]
private let s = Session.sharedInstance
private var nextOffsetE21Sle = 0
private var countOffsetE21Sle = 1000
private var nextOffsetE21 = 0
private var countOffsetE21 = 1000

func syncDb(){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.getSessionToken()
})
}

private func getSessionToken(){
postReq.sessionTokenRefresh { (done) in
if(done){
self.getReq.getTimeStampOfUpdatedTables({ (done) in
if(done){
if(self.s.e21TimeNeedUpdate){
self.deleteObject(1)
self.getDataForE21Table()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
if(self.s.e21sleTimeNeedUpdate){
self.deleteObject(2)
self.getDataForE21sleTable()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
if(self.s.evi22TimeNeedUpdate){
self.deleteObject(3)
self.getDataForE22()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
if(self.s.evi23ocTimeNeedUpdate){
self.deleteObject(4)
self.getDataForE23()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
if(self.s.regionTimeNeedUpdate){
self.deleteObject(5)
self.getDataForRegion()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
}
})
} else {
SwiftLoader.hide()
}
}
}

private func loadMoreDataE21Sle(){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
if(self.nextOffsetE21Sle <= self.countOffsetE21Sle) {
self.getDataForE21sleTable()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
})
}

private func loadMoreDataE21(){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("backgroundThread")
if(self.nextOffsetE21 <= self.countOffsetE21) {
self.getDataForE21Table()
} else {
Session.sharedInstance.progress += 0.2
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
})
}

private func getDataForE21Table(){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {

self.getReq.getE21(self.nextOffsetE21, count: self.countOffsetE21) { (done, id_pobor, misto, nazev_oc, gpsn, tel, ulice, exp_logo, gpse, id_obor, www, Id_prov, cinnost, psc, id_region, id_oblast, logo, provoz, eshop, count, next, doneDownloading) in
if(done){
self.saveToRealm.saveE21(id_pobor, misto: misto, nazev_oc: nazev_oc, gpsn: gpsn, tel: tel, ulice: ulice, exp_logo: exp_logo, gpse: gpse, id_obor: id_obor, www: www, Id_prov: Id_prov, cinnost: cinnost, psc: psc, id_oblast: id_oblast, logo: logo, provoz: provoz)
if(doneDownloading){
self.s.saveTableDates(self.s.e21Time, forKey: "e21Time")
self.nextOffsetE21 = self.nextOffsetE21 + 1000
self.countOffsetE21 = count
self.loadMoreDataE21()
}
} else {
SwiftLoader.hide()
}
}
})
}

private func getDataForE21sleTable(){
self.getReq.getE21sle(nextOffsetE21Sle, count: countOffsetE21Sle) { (done, vyse_sle, druh_sle, popis_sle, id_pobor, id_sle, id_prov, count, next, carte, doneDownloading) in
if(done){
self.saveToRealm.saveE21sle(vyse_sle, druh_sle: druh_sle, popis_sle: popis_sle, id_pobor: id_pobor, id_sle: id_sle, id_prov: id_prov, carte: carte)
if(doneDownloading){
self.s.saveTableDates(self.s.e21sleTime, forKey: "e21sleTime")
self.nextOffsetE21Sle = self.nextOffsetE21Sle + 1000
self.countOffsetE21Sle = count
self.loadMoreDataE21Sle()
}
} else {
SwiftLoader.hide()
}
}
}

private func getDataForE22(){
self.getReq.getE22 { (done, id_skup, skuptxt_sk, id_obor, skuptxt_cz, obortxt_sk, obortxt_cz, doneDownloading) in
if(done){
self.saveToRealm.saveE22(id_skup, skuptxt_sk: skuptxt_sk, id_obor: id_obor, skuptxt_cz: skuptxt_cz, obortxt_sk: obortxt_sk, obortxt_cz: obortxt_cz)
if(doneDownloading){
Session.sharedInstance.progress += 0.2
self.s.saveTableDates(self.s.evi22Time, forKey: "evi22Time")
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
} else {
SwiftLoader.hide()
}
}
}

private func getDataForE23(){
self.getReq.getE23oc { (done, nazev, psc, id_oc, oblast, sphere, misto, region, stat, statut, adresa, public_, doneDownloading) in
if(done){
self.saveToRealm.saveE23(nazev, psc: psc, id_oc: id_oc, oblast: oblast, sphere: sphere, misto: misto, region: region, stat: stat, statut: statut, adresa: adresa, public_: public_)
if(doneDownloading){
Session.sharedInstance.progress += 0.2
self.s.saveTableDates(self.s.evi23ocTime, forKey: "evi23ocTime")
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
} else {
SwiftLoader.hide()
}
}
}

private func getDataForRegion(){
self.getReq.getRegiony { (done, oblast, lokalita, okres, poradi, uroven, doneDownloading) in
if(done){
self.saveToRealm.saveRegion(oblast, lokalita: lokalita, okres: okres, poradi: poradi, uroven: uroven)
if(doneDownloading){
Session.sharedInstance.progress += 0.2
self.s.saveTableDates(self.s.regionTime, forKey: "regionTime")
NSNotificationCenter.defaultCenter().postNotificationName("checkForLoadedData", object: nil)
}
} else {
SwiftLoader.hide()
}
}
}

private func deleteObject(id:Int){
let realm = try! Realm()
try! realm.write {
switch id {
case 1: realm.delete(realm.objects(E21))
case 2: realm.delete(realm.objects(E21sle))
case 3: realm.delete(realm.objects(E22))
case 4: realm.delete(realm.objects(E23oc))
case 5: realm.delete(realm.objects(Regiony))
default:break
}
}
}


}

Answer

By default, Alamofire dispatches the response handler on the main queue (source). However, you can specify a different one using the queue: parameter of the response() method to keep the UI responsive:

    Alamofire.request(.GET, urlDomain + "_table/e21?offset=\(nextCheck)", headers: headers, encoding: .JSON)
        .responseJSON(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { response in

Keep in mind that if you do UI updates in the response handler, you need to do in in the main queue:

dispatch_async(dispatch_get_main_queue()) {
    // update some UI
}
Comments