2016-08-08 3 views
2

Я пытаюсь реализовать цепочку методов для успешных и неудачных вызовов в моем коде, но у меня, похоже, возникают проблемы с получением фактически вызванных методов onSuccess.Swift Method Chaining with Success & Failure

  1. Контроллер вида вызывает функцию getProduct(_:).
  2. getProduct(_:) делает вызов API, а затем вызывает storeProduct(_:) с извлеченной
  3. JSON
  4. storeProduct(_:) звонки fetchProduct(_:)
  5. fetchProduct(_:)doSuccess(_:) звонки, но это никогда не возвращается в onSuccess предыдущих вызовов.

Некоторые фрагменты кода

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 
} 

Я изначально INITIALIS ed chainable для каждой функции, но у этого были свои проблемы, из которых я думал (возможно, неправильно), что я должен только инициализировать classable класс один раз и передать его ссылку.

Некоторые сведения о том, куда я иду не так/что я мог бы попробовать, было бы здорово.

+2

Почему бы не использовать фреймворк вместо того, чтобы создавать свои собственные? Взгляните на перспективу; https://github.com/mxcl/PromiseKit –

+0

Это может быть так, как я иду, поскольку я уже потратил слишком много времени на попытку решить эту проблему. – Hodson

ответ

0

В соответствии с рекомендациями @John элементов, я решил использовать PromiseKit

Это не требует, чтобы много изменений коды и вот какие функции теперь выглядят как (все еще нужно сделать немного коды очистка, но она работает!):

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) 
     } 
    } 
} 
Смежные вопросы