Das Problem ist jetzt behoben. Siehe die letzte Bearbeitung für Details!Lange Verzögerung beim Drücken eines View-Controllers von GCD
Ich habe einen UIViewController mit einer Audiovisualisierung und einer Schaltfläche. Wenn eine Taste gedrückt wird, wird die folgende Funktion ausgelöst:
Hier erstelle ich eine Hintergrundwarteschlange und starte einen sehr langen Signalverarbeitungsvorgang. Sobald die Verarbeitung abgeschlossen ist, führe ich die Navigation zu einem anderen View-Controller aus, der die Hauptwarteschlange verwendet.
Dadurch erscheint ResultDetailViewController
auf dem Bildschirm mit allen relevanten Daten und der vollständig geladenen Visualisierung.
Jedoch, für die ersten 2-3 Sekunden nach dem VC geladen wurde, keiner der Knöpfe funktioniert! Wenn ich innerhalb dieser Anfangsperiode auf eine Schaltfläche klicke, wird die Aktion ausgelöst, sobald die Anfangsphase vorbei ist.
Wenn ich diesen Übergang von einem anderen VC durchführen, wird ResultDetailViewController
reibungslos geladen, und alles funktioniert.
Was mache ich falsch? Jede Hilfe würde sehr geschätzt werden!
EDIT 1
ich mehr Details über mein Set-up hinzufügen wird: In AnalysisController
, ich tue das folgende:
- Prozess das Signal FFT und solche
- -Update ein die Verwendung von Eigenschaften eines
global_result
- Trigger eine Methode
global_result
, die das Ergebnis in CoreData speichert und Alamofire verwendet, um die Daten an meinen Server POST
- Sobald der erste POST erfolgreich ist, aktualisiert der Callback die ID
global_result
und löst einige weitere POST-Anfragen aus. - Completion-Handler ausgelöst wird, die dann den Übergang
global_result
verursacht, ist mein benutzerdefiniertes globales Objekt, das als public var
initialisiert wird.
Theoretisch sollte der Beendigungshandler ausgelöst werden, sobald die Verarbeitung abgeschlossen ist, die Ergebnisse in CoreData gespeichert werden und die erste POST-Anforderung ausgelöst wird. unter Verwendung von Daten aus global_result
In ResultDetailViewController
‚s viewDidLoad
Funktion, bin ich das Kopieren global_result
in eine lokale Variable und die UI-Elemente zu schaffen.
Nun vermutete ich, dass die Verzögerung aufgrund Hintergrund-Thread tritt global_result
verwenden, wenn ResultDetailViewController
bereits geladen ist, so habe ich versucht, eine neue Instanz der Result
Klasse zu erstellen, anstatt die global_result
Kopieren, aber das auch nicht helfen.
Und hier ist die Result
Klasse:
import Foundation
import CoreData
import Alamofire
import CryptoSwift
public class Result {
var localID: Int
var id: Int
var filePath: NSURL!
var result: Double
var origSound: [Double]
init(localID: Int, id: Int, filePath: NSURL, result: Double, origSound: [Double]) {
// Initialize stored properties.
self.localID = localID
self.id = id
self.filePath = filePath
self.result = result
self.origSound = origSound
}
func store() {
self.storeLocal()
// Serialise data
let parameters = [
"localID": self.localID,
"id": self.id,
"result": self.result
]
// Prepare request
let request = NSMutableURLRequest(URL: NSURL(string: "my_server/script.php")!)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Encode parameters in JSON and encrypt them
request.HTTPBody = dictToEncryptedJSONData(rsaKey, parameters: parameters)
// POST the data to server
Alamofire.request(request)
.responseJSON { response in
if let JSON = response.result.value {
if let myID = JSON as? Int {
self.id = myID
// Store the global ID in CoreData
updateIDLocal(self.localID, id: self.id)
// Serialise and POST array
let param = [
"origSound": self.origSound
]
// Prepare request
var request = NSMutableURLRequest(URL: NSURL(string: "my_server/script2.php?id=\(self.id)")!)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Encode parameters in JSON and encrypt them
request.HTTPBody = dictToEncryptedJSONData(rsaKey, parameters: param)
// POST the data to server
Alamofire.request(request)
// Upload the file
let upURL = "my_server/script3.php?id=\(self.id)"
// Prepare request
request = NSMutableURLRequest(URL: NSURL(string: upURL)!)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Encrypt the file
request.HTTPBody = fileToEncryptedData(rsaKey, filePath: self.filePath)
// POST the data to server
Alamofire.request(request)
}
}
}
}
// Store the object in CoreData
func storeLocal() {
// Create a local id
if let oldID = NSUserDefaults.standardUserDefaults().integerForKey("localID") as Int? {
// Increment the ID
NSUserDefaults.standardUserDefaults().setInteger(oldID + 1, forKey: "localID")
self.localID = oldID + 1
}
else {
// First object in CoreData
NSUserDefaults.standardUserDefaults().setInteger(0, forKey: "localID")
}
// Store data in CoreData
var resultDatas = [NSManagedObject]()
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let entity = NSEntityDescription.entityForName("Result",
inManagedObjectContext:managedContext)
let resultData = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedContext)
// Store data
resultData.setValue(localID, forKey: "localID")
resultData.setValue(id, forKey: "id")
resultData.setValue(filePath.path!, forKey: "url")
resultData.setValue(result, forKey: "result")
// Store the array
var data = NSData(bytes: origSound, length: origSound.count * sizeof(Double))
resultData.setValue(data, forKey: "origSound")
//4
do {
try managedContext.save()
//5
resultDatas.append(resultData)
} catch _ {
print("Could not save")
}
}
}
Im AnalysisController
, ich rufe global_result.store()
EDIT 2
Was ich dachte, geschah, war dies:
- Erstellt einen Hintergrundthread
- Fertig schwere Verarbeitung auf diesem Thread
- eine POST-Anforderung an diesem Thread gesendet
- HTTP-Antwort verarbeitet wurde, und eine Menge von Daten wurde auf diesem Hintergrund-Thread
- an den Haupt-Thread verschlüsselten
- den Übergang Ausgeführte Jumped auf dem Haupt-Thread
In Wirklichkeit geschah dies:
- einen Hintergrund-Thread
- Fertig schwere Verarbeitung auf diesem Thread
- Gesendete eine POST-Anforderung auf diesem Thread
- gesprungen Hauptthread
- ausgeführt, um den Übergang von dem Hauptthread
- HTTP-Antworten plötzlich zurück kam Erstellt zu der Hauptthread, und es wurde blockiert, bis Tonnen von Daten die Verschlüsselung abgeschlossen haben.
Dank alexcurylo ‚s Vorschlag, und this SO thread, erkannte ich, dass die Antwort Handling Alamofire auf dem Hauptthread auftritt, so war es notwendig, einen kühlen Alamofire Funktion zu verwenden, um die Antwort drücken auf eine gleichzeitige Fadenhandhabungs, so die Hauptwarteschlange nicht zu blockieren.
Für die Zukunft ist jemand, implementiert ich es so auf:
// Prepare request
let request = NSMutableURLRequest(URL: NSURL(string: "my_server/script.php")!)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Encode parameters in JSON and encrypt them
request.HTTPBody = dictToEncryptedJSONData(rsaKey, parameters: parameters)
// Create a concurrent queue
let queue = dispatch_queue_create("DT.response-queue", DISPATCH_QUEUE_CONCURRENT)
// POST the data to server
Alamofire.request(request)
.response(
queue: queue,
responseSerializer: Request.JSONResponseSerializer(options: .AllowFragments),
completionHandler: { response in
// Perform response-handling HERE
})
Vielen Dank allen für Ihre Hilfe! Obwohl es dieses Problem nicht direkt löste, stellen Sandeep Bhandari 's Hintergrund Queue Creation Tip, und Igor B' s Methode für Storyboard-Referenzierung eine bessere Kodierungspraxis, die anstelle meines ursprünglichen Codes übernommen werden sollte.
Sind Sie etwas schwer auf Mainthread in viewDidLoad viewWillAppear oder viewDidAppear von ResultDetailViewController tun ??? –
In der ViewDidLoad-Methode von ResultDetailViewController lade ich einige Daten von CoreData ab und richte die UI-Elemente ein. Dieser VC lädt jedoch völlig in Ordnung, wenn er von irgendeinem anderen Teil meiner Anwendung aufgerufen wird, also vermute ich, dass das Problem an anderer Stelle liegt. –
Warum DISPATCH_QUEUE_CONCURRENT irgendetwas spezifisch ??? –