2016-08-08 16 views
2

Ich versuche, Methode Verkettung für Erfolg und Misserfolg Anrufe in meinem Code zu implementieren, aber ich habe Probleme mit der onSuccess Methoden tatsächlich aufgerufen werden.Swift Method Chaining mit Erfolg und Fehler

  1. Ein View-Controller ruft die getProduct(_:)-Funktion auf.
  2. getProduct(_:) macht einen API-Aufruf und ruft dann storeProduct(_:) mit dem abgerufenen json
  3. storeProduct(_:) Anrufe fetchProduct(_:)
  4. fetchProduct(_:) Anrufe doSuccess(_:) aber das wird nie wieder in die onSuccess der vorherigen Anrufe.

Einige Code-Schnipsel

BSProductChainable.swift

import Foundation 

class BSProductChainable<SuccessParams, FailureParams> { 

    var successClosure: ((SuccessParams) ->())? = nil 
    var failureClosure: ((FailureParams) ->())? = nil 

    func onSuccess(closure: (SuccessParams) ->()) -> BSProductChainable { 
     successClosure = closure 
     return self 
    } 
    func onFailure(closure: (FailureParams) ->()) -> BSProductChainable { 
     failureClosure = closure 
     return self 
    } 
    func doSuccess(params: SuccessParams) { 
     if let closure = successClosure { 
      closure(params) 
     } 
    } 
    func doFailure(params: FailureParams) { 
     if let closure = failureClosure { 
      closure(params) 
     } 
    } 
} 

BSProductManagerSwift.swift

class BSProductManagerSwift: NSObject { 

typealias productResponseChain = BSProductChainable<Product, NSError?> 
typealias productsResponseChain = BSProductChainable<[Product], NSError?> 

var serviceClient: BSNetworkingServiceClient! 
var objectContext: NSManagedObjectContext! 
var productChains: BSProductChainable<Product, NSError?>! 
var productsChains: BSProductChainable<[Product], NSError?>! 

convenience init(serviceClient: BSNetworkingServiceClient) { 
    self.init() 
    self.serviceClient = serviceClient 
    self.objectContext = managedObjectContext 
    self.productChains = BSProductChainable<Product, NSError?>() 
    self.productsChains = BSProductChainable<[Product], NSError?>() 
} 

func getProduct(ean: String) -> productResponseChain { 

    let urlString = BSConstants.BarcodeScanner.productEndpoint.stringByAppendingString(ean) 
    serviceClient.GET(urlString, failure: { (error) in 
     print("Could not get product") 
    }) { (response) in 
     if let json = response { 
      self.storeProduct(json).onSuccess({ (returedProduct) in 
       print("Stored product") 
      }) 
     } 
    } 

    return productChains 
} 

func storeProduct(json: JSON) -> productResponseChain { 

    fetchProduct(json["ean"].stringValue).onSuccess { (returedProduct) in 
     self.productChains.doSuccess(returedProduct) 
    } 

    return productChains 
} 

func fetchProduct(ean: String) -> productResponseChain { 

    let fetchRequest = NSFetchRequest(entityName: "Product") 
    let predicateEAN = NSPredicate(format: "%K == %@", "ean", ean) 
    let predicateMarket = NSPredicate(format: "%K == %@", "market", BSCountryManager.sharedInstance().getCurrentCountry().market) 
    let predicateLocale = NSPredicate(format: "%K == %@", "locale", BSLocalizationManager.sharedManager().currentLocalization.localeIdentifier()) 
    let predicateCurrency = NSPredicate(format: "%K == %@", "currency", BSLocalizationManager.sharedManager().currentLocalization.country.currencyIdentifierDMW) 
    let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateEAN, predicateMarket, predicateLocale, predicateCurrency]) 
    fetchRequest.predicate = compoundPredicate 

    do { 
     let matchingProuducts = try objectContext.executeFetchRequest(fetchRequest) 

     if matchingProuducts.count == 0 { 
      print("No matching products found") 
      let entity = NSEntityDescription.entityForName("Product", inManagedObjectContext: objectContext) 
      productChains.doSuccess(Product(entity: entity!, insertIntoManagedObjectContext: objectContext)) 
     } else { 
      print("Found matching product") 
      let d = matchingProuducts.first as! Product 
      productChains.doSuccess(d) 
     } 
    } catch let error as NSError { 
     print("Could not fetch \(error), \(error.userInfo)") 
     productChains.doFailure(error) 
    } 

    return productChains 
} 

ich zunächst Initialis edited die kettenfähige Klasse pro Funktion, aber dies hatte seine eigenen Probleme, von denen ich (möglicherweise fälschlicherweise) dachte, dass ich die kettenfähige Klasse nur einmal initialisieren und ihre Referenz weitergeben sollte.

Einige Eingabe, wo ich falsch liege/was ich als nächstes versuchen könnte, wäre großartig.

+2

Warum nicht ein Framework statt eigene zu bauen? Werfen Sie einen Blick auf Promekit; https://github.com/mxcl/PromiseKit –

+0

Das mag die Art sein, wie ich gehe, da ich bereits zu viel Zeit damit verbracht habe zu versuchen, dies zu lösen. – Hodson

Antwort

0

Wie @John Elemente empfohlen, habe ich beschlossen, PromiseKit

Das ist nicht zu viel von einer Codeänderung erfordert zu verwenden und hier sind, was jetzt die Funktionen aussehen (noch ein bisschen ein Code tun müssen Aufräumen, aber es funktioniert!):

func getProduct(ean: String) -> Promise<Product> { 
    return Promise { fullfill, reject in 
     let urlString = BSConstants.BarcodeScanner.productEndpoint.stringByAppendingString(ean) 
     serviceClient.GET(urlString, failure: { (error) in 
      reject(error!) 
     }) { (response) in 
      if let json = response { 
       self.storeProduct(json).then ({ returnedProduct in 
        print("We stored the product: \(returnedProduct.ean)") 
        fullfill(returnedProduct) 
       }).error { returnedError in 
        print("We had a problem storing the product: \(returnedError)") 
       } 
      } 
     } 
    } 
} 

func storeProduct(json: JSON) -> Promise<Product> { 
    return Promise { fullfill, reject in 
     fetchProduct(json["ean"].stringValue).then ({ returnedProduct in 

      var storedProduct: Product! 
      var isNewProduct = false 

      print("Fetched Product: \(returnedProduct.ean)") 

      isNewProduct = returnedProduct.valueForKey("ean") == nil 
      storedProduct = returnedProduct 
      storedProduct.setValue(json["name"].stringValue, forKey: "name") 
      storedProduct.setValue(json["ean"].stringValue, forKey: "ean") 
      storedProduct.setValue(json["image"].stringValue, forKey: "image") 
      storedProduct.setValue(json["price"].doubleValue, forKey: "price") 
      storedProduct.setValue(json["status"].intValue, forKey: "status") 
      storedProduct.setValue(json["pdp"].stringValue, forKey: "pdp") 
      storedProduct.setValue(BSCountryManager.sharedInstance().getCurrentCountry().market, forKey: "market") 
      storedProduct.setValue(BSLocalizationManager.sharedManager().currentLocalization.localeIdentifier(), forKey: "locale") 
      storedProduct.setValue(BSLocalizationManager.sharedManager().currentLocalization.country.currencyIdentifierDMW, forKey: "currency") 

      do { 
       try self.objectContext.save() 
       print("Stored Product: \(returnedProduct.ean)") 
       fullfill(returnedProduct) 

       if isNewProduct { 
        NSNotificationCenter.defaultCenter().postNotificationName("DidAddScanEntry", object: nil) 
       } 

      } catch let error as NSError { 
       print("Could not save \(error), \(error.userInfo)") 
       reject(error) 
      } 

     }).error { returnedError in 
      print("We had a problem fetching the product: \(returnedError)") 
      reject(returnedError) 
     } 
    } 
} 

func fetchProduct(ean: String) -> Promise<Product> { 
    return Promise { fullfill, reject in 

     let fetchRequest = NSFetchRequest(entityName: "Product") 
     let predicateEAN = NSPredicate(format: "%K == %@", "ean", ean) 
     let predicateMarket = NSPredicate(format: "%K == %@", "market", BSCountryManager.sharedInstance().getCurrentCountry().market) 
     let predicateLocale = NSPredicate(format: "%K == %@", "locale", BSLocalizationManager.sharedManager().currentLocalization.localeIdentifier()) 
     let predicateCurrency = NSPredicate(format: "%K == %@", "currency", BSLocalizationManager.sharedManager().currentLocalization.country.currencyIdentifierDMW) 
     let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateEAN, predicateMarket, predicateLocale, predicateCurrency]) 
     fetchRequest.predicate = compoundPredicate 

     do { 
      let matchingProuducts = try objectContext.executeFetchRequest(fetchRequest) 

      if matchingProuducts.count == 0 { 
       print("No matching products found") 
       let entity = NSEntityDescription.entityForName("Product", inManagedObjectContext: objectContext) 
       fullfill(Product(entity: entity!, insertIntoManagedObjectContext: objectContext)) 
      } else { 
       print("Found matching product") 
       let d = matchingProuducts.first as! Product 
       fullfill(d) 
      } 
     } catch let error as NSError { 
      print("Could not fetch \(error), \(error.userInfo)") 
      reject(error) 
     } 
    } 
}