无论如何,我可以避免使用似乎是某些"样板"码?

时间:2015-05-21 12:35:17

标签: swift generics

我从一个看起来像这样的函数开始:

    func getUser(command: APICommand, id: Int, handler: (apiResponse: APIResponse<User>) -> Void )  {
    let url = apiPath + "users/\(id)"
    Alamofire.request(.GET,  url, parameters: requestParameters)
        .responseObject { (a:NSURLRequest, b:NSHTTPURLResponse?, c:User?, d:AnyObject?, e:NSError? ) in
        let apiResponse = APIResponse(command: command,request: a, response: b, swiftObject: c, rawObject: d,  error: e)
        if AlamofireAPIRequestRepository.resultIsRetryableError(e, command: command) {
          println("retrying request")
          command.retry()
        } else {
          handler(apiResponse: apiResponse)
        }
    }
  }

我将会有许多看起来非常相似的函数,例如getUserList()

看着这个我意识到整个Alamofire.request电话将是锅炉板代码。唯一的区别是传递给闭包的参数类型c被responseObject()方法调用。在这种情况下,它是User?,在getUserList()方法中它将是UserList?

有什么方法可以让我更通用,并避免看起来只是&#34;样板&#34;码? 我这是我尝试过的。

  func alamofireGetRequest<T>(url: URLStringConvertible, parameters: [String: AnyObject]?,
    command: APICommand, handler: (apiResponse: APIResponse<T>) -> Void) -> Void {

          Alamofire.request(.GET,  url, parameters: parameters)
            .responseObject { (a:NSURLRequest, b:NSHTTPURLResponse?, c:T?, d:AnyObject?, e:NSError? ) in
              let apiResponse = APIResponse(command: command,request: a, response: b, swiftObject: c, rawObject: d,  error: e)
              if AlamofireAPIRequestRepository.resultIsRetryableError(e, command: command) {
                println("retrying request")
                command.retry()
              } else {
                handler(apiResponse: apiResponse)
              }
          }
      }

但是编译器抱怨:

  

无法调用&#39; responseObject&#39;使用类型的参数列表   &#39;((NSURLRequest,NSHTTPURLResponse?,T?,AnyObject?,NSError?) - &gt; _)&#39;

如果我更换c:T?上面用c:用户?很高兴。

下面的评论引用了这个question,这可以解释为什么我尝试的解决方案不起作用,但确实回答了我想要避免这些重复代码的问题。

1 个答案:

答案 0 :(得分:0)

我认为我找到了一个可以接受的解决方案。

下面是代码的相关部分,但基本上我最终将一个AnyObject的参数类型传递给闭包而不是泛型。在你说我在作弊之前,你必须明白我的原始电话会看起来像这样。

func testGetUserRequestSuccess() {
  let getUserCommand=commandFactory.createGetUserCommandUsing(apiRepo, id: 1) {
    if let swiftObject = $0.swiftObject {
      XCTAssertEqual(swiftObject.id!, 1, "id is correct")
    }
    self.expectation.fulfill()
  }
  commandProcessor.processCommand(getUserCommand)
  wait(5)
}

现在看起来像这样:

func testGetUserRequestSuccess() {
  let getUserCommand=commandFactory.createGetUserCommandUsing(apiRepo, id: 1) {
    if let swiftObject = $0.swiftObject as? User {
      XCTAssertEqual(swiftObject.id!, 1, "id is correct")
    }
    self.expectation.fulfill()
  }
  commandProcessor.processCommand(getUserCommand)
  wait(5)
}

所以我必须将as? User强制转换添加到if let语句中,这似乎是合理的。

任何感兴趣的人的相关代码。

&#34;专业&#34;代码(每个操作将重复的内容)

  func getUser(retriesUse retryProcessor: APICommandProcessor, command: APICommand, id: Int, handler: (apiResponse: APIResponse) -> Void )  {
    let url = apiPath + "users/\(id)"
    Alamofire.request(.GET,  url, parameters: requestParameters)
      .responseObject { (a:NSURLRequest, b:NSHTTPURLResponse?, c:User?, d:AnyObject?, e:NSError? ) in
        let apiResponse = APIResponse(command: command,request: a, response: b, swiftObject: c, rawObject: d,  error: e)
        self.finishResponse(command, retryProcessor: retryProcessor, apiResponse: apiResponse, handler: handler)
    } 
 }

我想要分解的共同部分(此时主要是占位符)

func finishResponse(command: APICommand, retryProcessor: APICommandProcessor, apiResponse: APIResponse, handler: (apiResponse: APIResponse) -> Void) -> Void {
      if AlamofireAPIRequestRepository.resultIsRetryableError(apiResponse.error, retryProcessor: retryProcessor, command: command) {
        println("retrying \(command)")
        retryProcessor.retryCommand(command)
      } else {
        println("request completed")
        handler(apiResponse: apiResponse)
      }
  }

上面使用的支持结构:

struct APIResponse {
  let command: APICommand
  let request: NSURLRequest
  let response: NSHTTPURLResponse?
  let swiftObject: AnyObject?
  let rawObject: AnyObject?
  let error: NSError?
}