如何不冻结UI并等待响应?

时间:2019-05-08 21:40:50

标签: ios swift asynchronous protocol-buffers grpc

从早上开始我一直在尝试,但是我没有达到我想要的。

我尝试了DispatchQueue.main.async和完成块,但是UI中的“提交”按钮仍然冻结,等待从服务器返回数据。这是我的代码:

func createData(request:Crudpb_CreateRequest, with completion: @escaping (String) -> Void) throws {
    DispatchQueue.main.async {
        self.response = try! self.client.create(request) // <---- How to handle error for this server call when the server is not available or is down?
        completion(self.response.result)
    }
}

我刚刚注意到我从以下代码中调用了第一个方法,这是一个同步一元函数,这可能是问题背后的原因。但是再次,我不知道如何在休假状态中调用第二个函数:

 /// Synchronous. Unary.
  internal func create(_ request: Crudpb_CreateRequest, metadata customMetadata: Metadata) throws -> Crudpb_CreateResponse {
    return try Crudpb_CrudServiceCreateCallBase(channel)
      .run(request: request, metadata: customMetadata)
  }
  /// Asynchronous. Unary.
  @discardableResult
  internal func create(_ request: Crudpb_CreateRequest, metadata customMetadata: Metadata, completion: @escaping (Crudpb_CreateResponse?, CallResult) -> Void) throws -> Crudpb_CrudServiceCreateCall {
    return try Crudpb_CrudServiceCreateCallBase(channel)
      .start(request: request, metadata: customMetadata, completion: completion)
  }

服务器端代码:

func (*server) Create(ctx context.Context, req *crudpb.CreateRequest) (*crudpb.CreateResponse, error) {

    var result string
    firstName := req.GetAccount().GetFirstName()
    lastName := req.GetAccount().GetLastName()
    //  id := gocql.TimeUUID()

    fmt.Println("Triggered CREATE function on Go Server " + firstName + " " + lastName + "! Yayy!")

    result = fmt.Sprintf("id for %s %s : %s", firstName, lastName, strconv.Itoa(rand.Intn(100)))
    return &crudpb.CreateResponse{
        Result: result,
    }, nil

在从服务器获取结果时,我需要此应用程序/提交按钮不冻结。

请帮助。

4 个答案:

答案 0 :(得分:1)

您仍在主线程上执行工作。async仅使createData()方法在任务完成之前返回。.但是任务仍会在某些时候处理在主线程中,在此期间您的应用程序将变得无响应 ..尝试使用全局队列代替..以保持主线程干净。

收到回复后,不要忘记在主线程上执行所有UI工作。

答案 1 :(得分:1)

请改用异步函数,并在create函数的完成内部调用完成块。

func createData(request:Crudpb_CreateRequest, with completion: @escaping (String) -> Void) throws { 
try! self.client.create(request) { (response: Crudpb_CreateResponse?, result: CallResult) in 
  DispatchQueue.main.async {
// This is assuming your completion involves UI operations. Otherwise there is no need for this async call.

let stringOutput = String(data: result.resultData!, encoding: String.Encoding.utf8))
    completion(stringOutput)
    }
  }
}

答案 2 :(得分:0)

从createData方法中删除DispatchQueue.main.async块

func createData(request:Crudpb_CreateRequest, with completion: @escaping (String) -> Void) throws {
    self.response = try! self.client.create(request)
    completion(self.response.result)
}

仅在从api响应更新UI的地方使用主队列

myobj.createData(request: request, with: { string in
    print(string)//background thread
    DispatchQueue.main.async {
        self.label.text = sting//main thread
    }
})

答案 3 :(得分:0)

UI冻结,因为您在主线程上做过多的工作。您应该找出什么功能阻塞了主线程。 工具time profiler是查看哪个功能花费过多时间的简便方法。