2015-10-28 22 views
7

ile çalışacak şekilde atama yapamadım Bir tamamlama işleyici ile mevcut işlevime bir throws eklemeye çalışıyorum ama no calls throwing functions occur within try expression diyerek bir uyarı almaya devam ediyorum. Ben hataları atmak bölümde,Tamamlama işleyicisi

invalid conversion from throwing function of type '() throwing -> Void' to non-throwing function type.

enum LoginError: ErrorType { 
    case Invalid_Credentials 
    case Unable_To_Access_Login 
    case User_Not_Found 
} 

@IBAction func loginPressed(sender: AnyObject) { 

    do{ 
     try self.login3(dict, completion: { (result) -> Void in 

          if (result == true) 
          { 
           self.performSegueWithIdentifier("loginSegue", sender: nil) 
          }      
         }) 
        } 
        catch LoginError.User_Not_Found 
        { 
         //deal with it 
        } 
        catch LoginError.Unable_To_Access_Login 
        { 
         //deal with it 
        } 
        catch LoginError.Invalid_Credentials 
        { 
         //deal with it 
        } 
        catch 
        { 
         print("i dunno") 
        } 

} 

func login3(params:[String: String], completion: (result:Bool) throws -> Void) 
{ 
    //Request set up 
    let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in 
    do { 
      let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves) as? NSDictionary 
      if let parseJSON = json 
      { 
       let userID = parseJSON["user_id"] as? Int 
       let loginError = parseJSON["user_not_found"] as? String 
       let validationError = parseJSON["invalid_credentials"] as? String 
       let exception = parseJSON["unable_to_access_login"] as? String 

       var responseArray = [(parseJSON["user_id"] as? Int)] 
       if userID != nil 
       { 
        dispatch_async(dispatch_get_main_queue()) { 
         completion(result:true) 
        } 

       } 
       else if loginError != "" 
       { 
        dispatch_async(dispatch_get_main_queue()){ 
         completion(result: false) 
         self.loginErrorLabel.text = loginError 
         throw LoginError.User_Not_Found 
        } 
       } 
       else if validationError != "" 
       { 
        dispatch_async(dispatch_get_main_queue()){ 
         completion(result:false) 
         self.validationErrorLabel.text = validationError 
         throw LoginError.Invalid_Credentials 
        } 

       } 
       else if exception != nil 
       { 
        dispatch_async(dispatch_get_main_queue()){ 
         completion(result:false) 
         self.exceptionErrorLabel.text = "Unable to login" 
         throw LoginError.Unable_To_Access_Login 
        } 
       } 
      } 
      else 
      { 
      } 
     } 
     catch let parseError { 
      // Log the error thrown by `JSONObjectWithData` 
     }) 

     task.resume() 

} 
+0

Bu bir eşzamansızlık işlevi. Geri dönüşünüzde, atmadığınız bir hatayı geri göndermeniz gerekir, programınızı attığınız anda bu fonksiyondan geri döndüğünüzde, o zaman işe yaramaz. – sbarow

+0

Biraz kafam karışık. Geri aramanın geri çağırma atmasını içeren işlevini atmasını mı yoksa atmamasını mı istiyorum? Ne tür bir hatanın atılacağını belirlemek için sunucudan gelen yanıtı bekliyorum, bu da geri çağrının atması gerektiğini düşünmemi sağlıyor. – Brosef

+0

@Victor Sigler cevabı sizin aradığınız şeydir. – sbarow

cevap

11

ne w ulaşmak için aşağıdaki kodda gibi throwable kapatılması içine hatayı enkapsüle yapabileceğim

func login3(params:[String: String], completion: (inner:() throws -> Bool) ->()) { 

    let task = session.dataTaskWithRequest(request, completionHandler: { data, response, error -> Void in 

      let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves) as? NSDictionary 

      if let parseJSON = json { 
       let userID = parseJSON["user_id"] as? Int 
       let loginError = parseJSON["user_not_found"] as? String 
       let validationError = parseJSON["invalid_credentials"] as? String 
       let exception = parseJSON["unable_to_access_login"] as? String 

       var responseArray = [(parseJSON["user_id"] as? Int)] 
       if userID != nil { 
       dispatch_async(dispatch_get_main_queue()) { 
        completion(inner: { return true }) 
       } 

      } 
      else if loginError != "" 
      { 
       dispatch_async(dispatch_get_main_queue()) { 
        self.loginErrorLabel.text = loginError 
        completion(inner: { throw LoginError.User_Not_Found }) 
       } 
      } 
      else if validationError != "" 
      { 
       dispatch_async(dispatch_get_main_queue()) { 
        self.validationErrorLabel.text = validationError 
        completion(inner: {throw LoginError.Invalid_Credentials}) 
       } 
      } 
      else if exception != nil 
      { 
       dispatch_async(dispatch_get_main_queue()){ 
        self.exceptionErrorLabel.text = "Unable to login" 
        completion(inner: {throw LoginError.Unable_To_Access_Login}) 
       } 
      } 
     } 
     else 
     { 
     } 
    } 

    task.resume() 
} 

Ve aşağıdaki şekilde gibi diyebilirsiniz: şapka istediğiniz

self.login3(dict) { (inner:() throws -> Bool) -> Void in 
    do { 
    let result = try inner() 
    self.performSegueWithIdentifier("loginSegue", sender: nil) 
    } catch let error { 
     print(error) 
    } 
} 

hüner login3 fonksiyon tipi () throws -> Bool ait 'inner' adında ek kapatılması almasıdır. Bu kapatma ya hesaplamanın sonucunu sağlar ya da atar.Bir hata durumunda

  • : kapatma kendisi iki vasıtalarından biri ile hesaplaması sırasında inşa edilmektedir inner: {throw error} başarı durumunda
  • : inner: {return result}

şiddetle size mükemmel makale tavsiye async çağrılarında try/catch kullanımı hakkında Using try/catch in Swift with asynchronous closures

Umarım bu size yardımcı olur.

+0

Oturum açma hatasını tamamlama bloğunda başka bir işleve atmak isterseniz, çalışmaz. –

0

inanmayarak aşağıda Oku söyleyerek bir hata alıyorum.

Sen tamamlama işleyicisi sorunu olur o taç atışı olan bir "dataTask" task yarattı, ancak login3 yönteminde sadece gerçek kod task.resume(): Ben henüz Swift 2.0 ile çok çalışmadım. Tamamlama işleyicisi, login3 döndükten sonra idam edilmeyecektir. (Aslında, başka bir nesnenin bir parametresidir, bu nedenle derleyici bu kodla ne olacağını bilemez.)

Anladığım kadarıyla, login3 yönteminizin gerçek alttan üste doğru gövdesi atmak. Bu bir async yöntemi olduğundan, bunu yapamazsınız. Bu nedenle, login3 işlevinizi atmayın. Bunun yerine, tamamlama işleyicisine bir hata nesnesi iletsin.

0

Benim izlenimimde bu, işlevlerinizin imzasından kaynaklanır. @IBAction func loginPressed(sender: AnyObject)'da, login3 numaralı telefonu çağırırken kullanmanız gerekmez; çünkü işlev, atma olarak işaretlenmez, ancak tamamlama işleyicisi açıktır. Ama aslında login3 tamamlama kapatma hiçbir zaman bir do {} catch {} bloğu içinde tüm atma işlevleri yürütürken atmak, böylece login3 tamamlama kapatma throws ek açıklama kaldırmak ve aynı zamanda bir hata ile login3 bir hata yakalarsanız kapatmayı arayabilir sonuca göre. Bu şekilde, login3'un içindeki tüm atma işlevlerini bir do {} catch {} bloğunda ele alırsınız ve tamamlama işleyicisini uygun bir değerle çağırın.

Genellikle @IBAction'da yaptığınız gibi önceki do {} bloğu olmadan yakalayabileceğinizi de bilmiyorum.

+0

Daha önce atılan Hataları doğrudan catch bloğunda yakalayacağınız için 'login3' içinde atmak da gereksizdir. Öneririm, hata koşullarına karşı kontrol etmektir ve tamamlanma kapamasını bir hatayla veya sizin durumunuzda yanlış sonuç olarak çağırır. Kapatma parametrelerini değiştirirseniz, kapatmaya bir hata iletebilirsiniz, ardından @IBAction değerinizde farklı hata koşullarını kontrol edebilirsiniz. – Daehn

0

ama her ihtimale karşı, Sen X için soruyorsun ve ben Y cevap veriyorum ...

yerine tamamlama işleyici fonksiyonunuza atma özelliği eklemek ihtimali de vardır:

func login3(params:[String: String], completion: (result:Bool) -> Void) throws { 
    ... 
} 

Sonra IBAction içinden diyebilirsiniz:

do { 
    try self.login3(dict) { result -> Void in 
     ... 
    } 
} catch { 
    print(error) 
} 
+0

Yaklaşımınızı denedim, ancak bir hataya yakalandım. 'Dispatch_async (dispatch_get_main_queue()) adresinden { self.loginErrorLabel.text = loginError tamamlama (iç: {throw LoginError.User_Not_Found}) }' Hâlâ geçersiz dönüştürme 'türünde bir işlev atma işlevinden hata alıyorum. atma -> Void 'atma olmayan işlev türüne. – Brosef

+0

@Brosef Bu sürümde tamamlanmalarınızı değiştirmeye gerek yok, onları olduğu gibi saklayın ("iç" şeyler). Gösterdiğimden başka bir şeye gerek yok. – Moritz

+0

Çözümünüzü uygulamaya çalışıyorum ama eğer 'throw'' dispatch_async 'içine yerleştirirsem, önceki yorumumda anlattığım hatayı alıyorum. – Brosef

İlgili konular