2017-02-03 1 views
0

Ich bin Swift etwas neu und habe meistens herausgefunden, wie man mit Hilfe dieser Seite die Vervollständigungshandler benutzt. Nach einigen Tagen, in denen ich versuchen würde, dies zur Arbeit zu bringen, würde ich mir mehr direkte Hilfe wünschen.Wie kann ich sicherstellen, dass diese Funktion abgeschlossen ist, bevor ich die Antwort interpretiere?

Ich habe ein:

@IBAction func submitRegistrationButton(_ sender: Any) { 

    if((firstNameField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){ 
     showXAlert(title: "Oops!", message: "Please enter your first name.", viewController: self) 
    }else if((lastNameField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){ 
      showXAlert(title: "Oops!", message: "Please enter your last name.", viewController: self) 
     }else if((emailAddressField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){ 
       showXAlert(title: "Oops!", message: "Please enter your email address.", viewController: self) 
      }else if !isValidEmail(testStr: emailAddressField.text!){ 
        showXAlert(title: "Oops!", message: "Please enter a valid email address.", viewController: self) 
       }else if((passwordField.text?.trimmingCharacters(in: .whitespacesAndNewlines).characters.count) == 0){ 
        showXAlert(title: "Oops!", message: "Please enter a password.", viewController: self) 
        }else if passwordField.text != passwordConfirmationField.text{ 
         showXAlert(title: "Oops!", message: "Your password and password confirmation do not match. Please correct.", viewController: self) 
       }else{ 
        registrant.firstName = firstNameField.text! 
        registrant.lastName = lastNameField.text! 
        registrant.zipCode = zipCodeField.text! 
        registrant.emailAddress = emailAddressField.text! 
        registrant.password = passwordField.text! 
        storeRegistrationInfo(registrant: registrant) { (object: XUserAPIResult) in 

         print("submissionStatus = \(object.success)") 

         if object.success == 1 { 
          showXAlert(title: "Welcome \(self.registrant.firstName)!", message: "Your registration was submitted successfully. Log in by clicking the Login button below", viewController: self) 
         }else{ 
         showXAlert(title: "Un Oh", message: "There was a problem with your registration. \(object.errorMessage)", viewController: self) 
         } 

        } 
       } 
} 

... das nennt:

func storeRegistrationInfo(registrant: XRegistrantInfo, finished: @escaping (XUserAPIResult)->()) { 
    var apiResult = XUserAPIResult() 

    let appDelegate = UIApplication.shared.delegate as! AppDelegate 

    let context = appDelegate.persistentContainer.viewContext 

    let newRegistrant = NSEntityDescription.insertNewObject(forEntityName: "User", into: context) 

    let requestURL = NSURL(string: USER_API_URL) 
    let request = NSMutableURLRequest(url: requestURL! as URL) 

    request.httpMethod = "POST" 

    newRegistrant.setValue(registrant.firstName, forKey: "firstName") 
    newRegistrant.setValue(registrant.lastName, forKey: "lastName") 
    newRegistrant.setValue(registrant.zipCode, forKey: "zipCode") 
    newRegistrant.setValue(registrant.emailAddress, forKey: "emailAddress") 
    newRegistrant.setValue(registrant.password, forKey: "password") 
    newRegistrant.setValue(registrant.personna, forKey: "personna") 
    do{ 
     try context.save() 
     let postParameters = "tag=" + REGISTRATION_API_TAG + "&firstName=" + registrant.firstName + "&lastName=" + registrant.lastName + "&password=" + registrant.password + "&username=" + registrant.emailAddress + "&personna=" + registrant.personna + "&zipCode=" + registrant.zipCode 
     request.httpBody = postParameters.data(using: .utf8) 
     let task = URLSession.shared.dataTask(with: request as URLRequest){ 
      data, response, error in 

      if error != nil{ 
       print("error is \(error)") 
       return 
      } 

      print("response = \(response)") 
      //parsing the response 
      do { 
       //converting resonse to NSDictionary 
       let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary 

       //parse json 2 

       if let dictionary = myJSON as? [String: Any]{ 
        if let apiSuccess = dictionary["success"] as? Int{ 
         apiResult.success = apiSuccess 
        } 
        if let apiError = dictionary["error"] as? Int{ 
         apiResult.error = apiError 
         if apiError != 0{ 
          if let apiErrorMessage = dictionary["error_msg"] as? String{ 
           apiResult.errorMessage = apiErrorMessage 
          } 

         }else{ 
          if let apiUID = dictionary["uid"] as? String{ 
           apiResult.uniqueID = apiUID 
          } 
          if let nestedDictionary = dictionary["user"] as? [String: Any]{ 
           if let apiFirstName = nestedDictionary["firstName"] as? String{ 
            apiResult.user.firstName = apiFirstName 
           } 
           if let apiLastName = nestedDictionary["lastName"] as? String{ 
            apiResult.user.lastName = apiLastName 
           } 
           if let apiEmail = nestedDictionary["e-mail"] as? String{ 
            apiResult.user.emailAddress = apiEmail 
           } 
           if let apiCreatedAt = nestedDictionary["created_at"] as? String{ 
            apiResult.user.createdAt = apiCreatedAt 
           } 
           if let apiPersonna = nestedDictionary["personna"] as? String{ 
            apiResult.user.personna = apiPersonna 
           } 
          } 
          finished(apiResult) 
         } 
        } 
       } 
      } catch { 
       print(error) 
      } 
     } 
     task.resume() 
     finished(apiResult) 
    } catch { 
     print("There was an error saving to Core Data") 
     finished(apiResult) 
    } 
} 

Die submitRegistrationButton() Code soll bis storeRegistrationInfo warten() eine XUserAPIResult kehrt struct und dann den entsprechenden Alarm basierend auf XUserAPIResult anzeigen Erfolgseigenschaft.

Das Problem besteht darin, dass der Erfolgsprüfungscode ausgeführt wird, bevor storeRegistrationInfo() die JSON-Analyse abschließt; Anzeige der falschen Warnung und dann korrekt ausgeführt, nachdem der JSON analysiert wurde. Die anderen Aspekte des Codes (der Web-API-Aufruf, das Parsen des JSON, das Speichern der Daten in der Web-Datenbank) funktionieren.

Ich bin mir ziemlich sicher, dass etwas falsch ist mit, wie ich den Abschluss-Handler oder den Aufruf von storeRegistrationInfo(), aber ich bin mir nicht sicher, wie genau es zu beheben.

Wie kann ich sicherstellen, dass der Alarm Code in @IBAction func submitRegistrationButton (_ Absender: Any):

storeRegistrationInfo(registrant: registrant) { (object: XUserAPIResult) in 

    print("submissionStatus = \(object.success)") 

    if object.success == 1 { 
     showXAlert(title: "Welcome \(self.registrant.firstName)!", message: "Your registration was submitted successfully. Log in by clicking the Login button below", viewController: self) 
    }else{ 
     showXAlert(title: "Un Oh", message: "There was a problem with your registration. \(object.errorMessage)", viewController: self) 
    }  
} 

... erst nach dem JSON analysiert wird aufgerufen und die UserAPIResult Struktur ist bevölkert und zurückgegeben?

Danke.

Antwort

0

Das Problem in Ihrem Code ist die Linie hier:

task.resume() 
finished(apiResult) 

Sie den Anruf entfernen sollte der finished Abschluss-Handler, da dieser an der Stelle aufgerufen werden sollte, an der er bereits plaziert ist ed, nachdem die Antwort erhalten wurde.

Ein weiterer Verbesserungsvorschlag für Sie wäre, Ihren Feldüberprüfungscode zu vereinfachen, um guard Anweisungen zu verwenden.

+0

Danke! Das scheint es behoben zu haben! Ich werde Ihrem Rat bezüglich der Wächterstatements folgen ... – Wayne

+0

... Ich sage "scheint" oben, weil die App jetzt abstürzt, nachdem die Warnung "Willkommen ..." angezeigt wird.Ich weiß nicht, ob das zusammenhängt. – Wayne

+0

Um diese Frage und für jeden anderen, der das gleiche Problem hat, zu schließen, dank [diesem Thread] (http://stackoverflow.com/questions/37801370/how-do-i-dispatch-sync-dispatch-async-dispatch -after-etc-in-swift-3) Ich erkannte, dass 'showXAlert()' versuchte, die Warnung von einem anderen Thread als dem Haupt-Thread zu präsentieren. Das hat den Absturz verursacht. – Wayne

0

versuchen die folgende

typealias CompletionHandler = (data:XRegistrantInfo,success:Bool) -> Void; 


func storeRegistrationInfo(registrant: XRegistrantInfo,completionHandler: CompletionHandler) { 
    // your code. 
    // 
    // 
    completionHandler(data: dataToReturn,success : true/false) 
} 

Und der Anruf wird als

storeRegistrationInfo(registrant, { (data,success) -> Void in 
    //onCompletion the code will go here 
    if success { 
     // success 
    } else { 
     // fail 
    } 
}) 
+0

Danke Moin. Ich habe gerade eine kurze Recherche über 'typalias' gemacht. Schlägst du dies vor, um die Wartbarkeit/Lesbarkeit des Codes zu verbessern? Gibt es einen Grund, warum Sie eine "Erfolg: Bool" versus, wie ich es derzeit habe, die "Erfolg: Int" -Eigenschaft einer XUserAPIResult-Instanz? – Wayne

+0

Wenn der Rückgabetyp nur zwischen 2 Werten wechselt, dann bevorzuge ich normalerweise bool, und wenn es mehr als dann aber in einer Sequenz ist, dann enum – Moin

Verwandte Themen