2016-06-12 2 views
0

In App-Delegate, nachdem ich die Koordinaten des Benutzers mit Kernstandort abrufen möchte, möchte ich zwei API-Aufrufe vornehmen. Einer ist zu meinem Server, um eine Kugel des Stadtnamens zu bekommen, in dem wir uns befinden. Der Aufruf ist asynchron, also möchte ich den gesamten Inhalt in ein globales Variablenfeld laden, bevor ich den zweiten Aufruf von Google Maps api mache, um den Städtenamen von Google zu erhalten, auch mit einem Async-Aufruf. Und schließlich, nachdem ich alle Google-Daten geladen habe, möchte ich die beiden Arrays vergleichen, mit den Städtenamen einen Zufall finden. Um das zu tun, müssen die ersten beiden Operationen beendet sein. Dafür verwende ich Closures, um sicherzustellen, dass alle Daten vor dem nächsten Start geladen werden. Aber wenn ich mein Programm starte, findet es keinen Zufall zwischen den beiden Arrays und wenn ich Breakpoints setze, sehe ich, dass das zweite Array (google) geladen wird, nachdem der Vergleich gemacht wird, was sehr frustrierend ist, weil ich es habe Stellen Sie viele Schließungen ein, und zu diesem Zeitpunkt kann ich die Quelle meines Problems nicht finden. Jede Hilfe wäre willkommen.Schließungen in Swift tun was auch immer. Meine Codeausführung verhält sich nicht wie angenommen

dies AppDelegate:

let locationManager = CLLocationManager() 

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 
    // Override point for customization after application launch. 

    //Language detection 
    let pre = NSLocale.preferredLanguages()[0] 
    print("language= \(pre)") 

    //Core Location 
    // Ask for Authorisation from the User. 
    self.locationManager.requestAlwaysAuthorization() 

    //Clore Location 
    // For use in foreground 
    self.locationManager.requestWhenInUseAuthorization() 
    if CLLocationManager.locationServicesEnabled() { 
     locationManager.delegate = self 
     locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters 
     locationManager.startUpdatingLocation() 


     //Load cities slug via api call 
     let apiCall : webApi = webApi() 

     apiCall.loadCitySlugs(){(success) in 
      //Slug loaded in background 
      //Call google api to compare the slug 
      apiCall.loadGoogleContent(){(success) in //this function is called after compareGoogleAndApiSlugs() 
       apiCall.compareGoogleAndApiSlugs() //this one called before 
      } 
     } 

    } 
    return true 
} 

Diese meine globalen Variablen swift Datei ist:

import Foundation 
import CoreLocation 
let weatherApiKey : String = "" //weather api key 
var globWeatherTemp : String = "" 
var globWeatherIcon : String = "" 
var globCity : String = "" 
var globCountry : String = "" 
let googleMapsApiKey : String = "" 
let googlePlacesApiKey : String = "" 
var TableData:Array<String> = Array <String>() 
var nsDict = [] 
var locValue : CLLocationCoordinate2D = CLLocationCoordinate2D() 


typealias SuccessClosure = (data: String?) -> (Void) 
typealias FinishedDownload =() ->() 
typealias complHandlerAsyncCall = (success : Bool) -> Void 
typealias complHandlerCitySlug = (success:Bool) -> Void 
typealias complHandlerAllShops = (success:Bool) -> Void 
typealias googleCompareSlugs = (success:Bool) -> Void 

var flagCitySlug : Bool? 
var flagAsyncCall : Bool? 
var flagAllShops : Bool? 

var values : [JsonArrayValues] = [] 
var citySlug : [SlugArrayValues] = [] 

var asyncJson : NSMutableArray = [] 
let googleJson : GoogleApiJson = GoogleApiJson() 

dies ist die erste Funktion in AppDelegate genannt, die einen Anruf auf meinen Server machen zu laden die Stadt slug:

func loadCitySlugs(completed: complHandlerCitySlug){ 

    //Configure Url 
    self.setApiUrlToGetAllSlugs() 

    //Do Async call 
    asyncCall(userApiCallUrl){(success)in 

     //Reset Url Async call and Params 
     self.resetUrlApi() 

     //parse json 
     self.parseSlugJson(asyncJson) 

     flagCitySlug = true 
     completed(success: flagCitySlug!) 
    } 
} 

Dies ist die zweite Funktion, laden Sie Google-Inhalte, aber es ist ca gefüllt nach compareGoogleAndApiSlugs() und es sollte vor aufgerufen werden ...

/* 
Parse a returned Json value from an Async call with google maps api Url 
*/ 
func loadGoogleContent(completed : complHandlerAsyncCall){ 

    //Url api 
    setGoogleApiUrl() 

    //Load google content 
    googleAsyncCall(userApiCallUrl){(success) in 

    //Reset API URL 
    self.resetUrlApi() 
    } 
    flagAsyncCall = true // true if download succeed,false otherwise 

    completed(success: flagAsyncCall!) 
} 

Und schließlich die Asynchron-Anrufe gibt es zwei, aber sie sind fast der gleiche Code:

/** 
Simple async call. 
*/ 
func asyncCall(url : String, completed : complHandlerAsyncCall)/* -> AnyObject*/{ 

    //Set async call params 
    let request = NSMutableURLRequest(URL: NSURL(string: url)!) 
    request.HTTPMethod = "POST" 

    request.HTTPBody = postParam.dataUsingEncoding(NSUTF8StringEncoding) 
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in 
     guard error == nil && data != nil else { 
      // check for fundamental networking error 
      print("error=\(error)") 
      return 
     } 
     if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 { 
      // check for http errors 
      print("statusCode should be 200, but is \(httpStatus.statusCode)") 
      print("response = \(response)") 
     } 


     let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding) 

     asyncJson = responseString!.parseJSONString! as! NSMutableArray 

     flagAsyncCall = true // true if download succeed,false otherwise 

     completed(success: flagAsyncCall!) 

    } 
    task.resume() 

} 

Wenn jemand sehen das Problem oder ein wenig Licht werfen würde es sehr geschätzt werden.

Antwort

1

Das Problem ist, diese Funktion:

func loadGoogleContent(completed : complHandlerAsyncCall){ 

    setGoogleApiUrl() 
    googleAsyncCall(userApiCallUrl){(success) in 

     self.resetUrlApi() 
    } 
    flagAsyncCall = true 
    completed(success: flagAsyncCall!) //THIS LINE IS CALLED OUTSIDE THE googleAsyncCall.. 
} 

Die obige Fertigstellung Block außerhalb des googleAsyncCall Block genannt wird. sein

sollte der Code:

func loadGoogleContent(completed : complHandlerAsyncCall){ 

    setGoogleApiUrl() 
    googleAsyncCall(userApiCallUrl){(success) in 

     self.resetUrlApi() 
     flagAsyncCall = true 
     completed(success: flagAsyncCall!) 

    } 
} 

Btw .. Ihre globalen Variablen nicht atomar sind .. so vorsichtig sein.

+0

Entschuldigung, können Sie etwas mehr erklären, was das Problem sein kann, wenn die Variable nicht atomar ist? Ich bin neu in Swift und diese Informationen können sehr hilfreich für mich sein. Möchten Sie auch nach dem globalen Variablenvervollständigungs-Handler fragen, er muss immer global sein? Gibt es nicht eine Möglichkeit, mit Einheimischen Komplementär zu machen? Möchte auch wissen, ob ich diese globalen Variablen wiederverwenden kann? Wie kann ich sie wieder auf false setzen? Und vielen Dank, denn deine Antwort hat mein Problem gelöst! – user3033437

+0

Wenn die Variable nicht atomar ist und mehrere Threads gleichzeitig zum Schreiben darauf zugreifen, in welchem ​​Zustand befindet sich die Variable noch? Jeder Thread kann einen anderen Wert sehen. Nein, Sie brauchen nicht immer globale Variablen. Tatsächlich brauchen Sie sie wahrscheinlich fast nie. Ja, Sie können sie wiederverwenden. – Brandon

Verwandte Themen