You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift-Alamofire调用函数时Completion Handler未执行问题求助

问题:API请求完成后Completion Handler未触发,Realm读取数组为空

问题详情

定义了如下Swift函数用于API请求并存储数据到Realm:

typealias Handler = (Swift.Result<Any?, APIErrors>) -> Void

func viewApi (ownerId: String, accessToken: String, completionHandler: @escaping Handler ){
var viewArray: [Information] = [Information]()
    
    let headers: HTTPHeaders = [
            
        .authorization("Bearer \(accessToken)")
    
    ]
    
    let viewUrl = "\(viewTaskUrl)?userId=\(ownerId)"
           
    let url = URL(string: viewUrl)
    var request = URLRequest(url: url!)
   
    request.method = .get
    request.headers = headers
    
    var taskList:[Task] = []
    
    AF.request(request).responseJSON(completionHandler: { (response) in
        
        var holder = Information(id: 0, title: "", description: "", status: "")
        switch response.result {
            
        case .success(let data):
            do{
                if response.response?.statusCode == 200 {
//                        completionHandler(.success("JSON HERE: \

    (String(describing: json))"))
                        let jsonData = try JSONSerialization.data(withJSONObject: data)
                        let jsonString = String(data: jsonData, encoding: .utf8)
                    
                    let trySplit = jsonString?.components(separatedBy: ",")
                    
                    for i in 0...trySplit!.count-1{

                        if trySplit![i].contains("id"){
                            let id = trySplit![i].components(separatedBy: ":")[1]
                            holder.id = Int(id)!
                        }

                        if trySplit![i].contains("title"){

                            let title = trySplit![i].components(separatedBy: ":")[1]
                            holder.title = title
    //                            print("TITLE: \(title)")
                            
                        }
                        
                        if trySplit![i].contains("description"){

                            let desc = trySplit![i].components(separatedBy: ":")[1]
                            holder.description = desc
                            
                        }
                        
                        if trySplit![i].contains("status"){

                            let stat = trySplit![i].components(separatedBy: ":")[1]
                            let edited = stat.replacingOccurrences(of: "}", with: "")
                            holder.status = edited
                            
                            viewArray.append(holder)
                            
                        }
                    }
                }else{
//                       completionHandler(.failure(.custom(message: "Please check your network connectivity")))
                    print("Error")
                }
            
            }catch{
                
                print(error.localizedDescription)
                
            }
            
            case .failure(let err):
            print (err)
            
        }
        print("ARRAY: \(viewArray)")
        for i in 0 ..< viewArray.count {
            
            let task = Task()
            
            let edited = viewArray[i].status.replacingOccurrences(of: "]", with: "")
            let new = viewArray[i].title.replacingOccurrences(of: "\"", with: "")
            
            task.taskName = new
            task.id = viewArray[i].id
            task.taskStatus = edited
            task.taskDescription = viewArray[i].description
            task.email = ownerId
            
            taskList.append(task)
        }
        try! self.realm.write{
            self.realm.add(taskList)
        }
        
    }).resume()
    
}

该函数可正常获取JSON并写入Realm,但在ViewController调用时,Completion Handler未执行,且立刻读取Realm时返回空数组:

self.APIManager.viewApi(ownerId: self.userId!, accessToken: self.token!) { (result) in
            switch result{
            case .success(_):
                //does not run
                print("SUCCESS COMPLETION")
            case .failure(let err):
                print(err.localizedDescription)
            }
        }

需求:让函数执行完成后触发后续代码,确保读取Realm数组不为空且Completion Handler正常触发。

注:暂时忽略JSON处理的粗糙实现,后续会优化


解决方案

1. 补全Completion Handler的调用

问题核心是你在viewApi函数中从未调用传入的completionHandler闭包,这是导致ViewController中闭包不执行的直接原因。需要在所有请求分支中添加调用:

修改后的viewApi关键部分:

AF.request(request).responseJSON(completionHandler: { (response) in
    // ... 原有JSON解析、数组组装逻辑保持不变 ...
    
    switch response.result {
    case .success(let data):
        do{
            if response.response?.statusCode == 200 {
                // ... JSON解析逻辑 ...
                
                // 请求成功且解析完成后调用success分支
                completionHandler(.success(taskList)) // 可传入需要的数据,比如组装好的taskList
            }else{
                let error = APIErrors.custom(message: "请求失败,状态码:\(response.response?.statusCode ?? 0)")
                completionHandler(.failure(error))
                print("Error")
            }
        }catch{
            let error = APIErrors.custom(message: error.localizedDescription)
            completionHandler(.failure(error))
            print(error.localizedDescription)
        }
    case .failure(let err):
        let error = APIErrors.custom(message: err.localizedDescription)
        completionHandler(.failure(error))
        print(err)
    }
    
    // ... Realm写入逻辑 ...
    try! self.realm.write{
        self.realm.add(taskList)
    }
    // 可选:如果需要确保Realm写入完成后再通知回调,可将completionHandler移到这里
}).resume()

2. 在Completion Handler中读取Realm数据

网络请求和Realm写入都是耗时/异步操作,不能在调用viewApi后立刻读取Realm数据,必须等待completionHandler触发后再执行读取逻辑:

修改后的ViewController调用代码:

self.APIManager.viewApi(ownerId: self.userId!, accessToken: self.token!) { [weak self] (result) in
    guard let self = self else { return }
    switch result{
    case .success(_):
        print("SUCCESS COMPLETION")
        // 此时Realm已写入完成,在这里读取数据
        do {
            let realm = try Realm()
            let tasks = realm.objects(Task.self).filter("email == %@", self.userId!)
            let taskArray = Array(tasks)
            print("读取到的Realm数据:\(taskArray)")
            // 后续UI更新或业务逻辑放在这里
            DispatchQueue.main.async {
                // 若需更新UI,切换到主线程执行
            }
        } catch {
            print("Realm读取失败:\(error.localizedDescription)")
        }
    case .failure(let err):
        print(err.localizedDescription)
    }
}

额外注意事项

  • 避免使用try!,建议用do-catch处理Realm操作异常,防止崩溃
  • 网络请求回调默认在后台线程,若需更新UI,必须切换到主线程执行

内容的提问来源于stack exchange,提问作者Tristan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:45:33