为什么Swift @转义闭包不起作用?

时间:2020-11-11 03:06:32

标签: ios swift swiftui

我正在尝试在加载应用程序(iOS)主视图时显示客户列表。数据是从JSON格式的API请求返回的,我确认我已进入调试器。我在从主视图获取响应时遇到问题,因为在视图加载方法完成后会调用fetch方法。如我所读,我应该在fetch方法中添加一个完成处理程序,并将其作为转义的附件传递,以便main方法等待fetch方法。我遵循此guide并阅读了几次,但仍然无法找到错误所在。我想念什么?

  1. 这是我正在调用搜索方法的SwiftUI视图:
    struct CustomerList: View {
    
    @State var customerList = searchCustomer(criteria: "jose")
    
    
    
    var body: some View {
        List(self.customerList, id: \.id){ customer in
            CellRow(customer: customer)
        
        }
     }
    }
  1. 这是在视图加载事件中调用的搜索功能(实际上是一个功能,不属于任何类或结构的一部分)
    func searchCustomer(criteria: String) -> [Customer] {
    
    //API call full url
    let fullURL = FTP_API_URL + criteria
    var customerList = [Customer]()
    
    if criteria == ""{
        return customerList
    }
    
    getJsonFromAPI(url: fullURL, fetchCompletionHandler: {customers, error in
        
        if let jsonCustomers = customers{
            customerList = jsonCustomers.customers
        }
    })
    return customerList
  }
  1. 获取异步函数(实际上是一个函数,不属于任何类或结构)
func getJsonFromAPI(url: String, fetchCompletionHandler : @escaping (Customers?, Error?)-> Void){
    
    let username = decryptData(data: FTP_API_USERNAME)
    let password = decryptData(data: FTP_API_PASSWORD)
    
    let loginData = String(format: "%@:%@", username, password).data(using: String.Encoding.utf8)!
    let base64LoginData = loginData.base64EncodedString()
    
    
    // create the request
    let url = URL(string: url)!
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("Basic \(base64LoginData)", forHTTPHeaderField: "Authorization")
    
    //making the request
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        
        guard let data = data, error == nil else {
            print("\(error)")
            return
            
            
        }
        
        //if let httpStatus = response as? HTTPURLResponse {
        // check status code returned by the http server
        //print("status code = \(httpStatus.statusCode)")
        // process result
        //        }
        
        let jsonDecoder = JSONDecoder()
        
        do{
            
            let results = try jsonDecoder.decode(Customers.self, from: data)
            
            //            for result in results.customers{
            //                print(result.cedulaOrPassport)
            //            }
            
            fetchCompletionHandler(results, nil)
            
        }
        catch{
            print(error)
            fetchCompletionHandler(nil, error)
        }
        
    }
    task.resume()
    
    
}

谢谢。

1 个答案:

答案 0 :(得分:0)

当数据(从return customerList异步获取)尚不可用时,searchCustomer中的

getJsonFromAPI同步发生。因此,您正在分配[Customer]并将其@State var customerList空数组。

无论如何,您不能直接将异步获取的值分配给属性。

相反,将searchCustomer更改为也接受完成处理程序,并使用.onAppear调用它并从完成处理程序中分配值(就像使用getJsonFromAPI一样):< / p>

func searchCustomer(criteria: String, 
                    completionHandler: @escaping ([Customer]) -> Void) -> Void {
    
    //API call full url
    let fullURL = FTP_API_URL + criteria
    var customerList = [Customer]()
    
    if criteria == "" {
        completionHandler(customerList)
    }
    
    getJsonFromAPI(url: fullURL, fetchCompletionHandler: {customers, error in
        
        if let jsonCustomers = customers{
            customerList = jsonCustomers.customers
            completionHandler(customerList)
        }
    })
  }
struct CustomerList: View {
    
    @State var customerList = []

    var body: some View {
        List(self.customerList, id: \.id){ customer in
            CellRow(customer: customer)
        }
        .onAppear() {
           searchCustomer(criteria: "jose") { customers in
              customerList = customers
           }
        }
    }
}