如何修复Swift字典循环代码,实现逐个询问并等待输入?
修复Swift字典遍历的交互式询问代码
我来帮你搞定这个问题!你想要遍历字典里的每一个成员,逐个询问是否参加,并且等用户输入后再进行下一个,对吧?原来的for循环是同步执行的,没法停下来等用户的异步输入(比如弹窗选择),所以我们需要用异步的方式来控制遍历节奏,下面是几种可行的方案:
方案一:使用Async/Await(推荐,适配iOS 15+、macOS 12+)
这个方法利用Swift的异步等待特性,让遍历过程在每个询问后暂停,等用户做出选择再继续,代码更简洁易读:
import Foundation import UIKit class AttendeeManager: UIViewController { var squad = [1:"Arsh", 2:"Arbab", 3:"Ayush", 4:"KC", 5:"Jaski", 6:"Gunny", 7:"Harsh", 8:"Nagib", 9:"Rithin", 10:"Gursh", 11:"Sonny"] var attendees = [String]() override func viewDidLoad() { super.viewDidLoad() // 启动异步遍历任务,不阻塞主线程 Task { await askAttendeesSequentially() // 所有询问完成后,输出结果 print("最终参会名单:\(attendees)") } } private func askAttendeesSequentially() async { // 先按字典的key排序,保证询问顺序固定(字典默认无序) for (_, name) in squad.sorted(by: { $0.key < $1.key }) { let isComing = await askUserAboutAttendee(name: name) if isComing { attendees.append(name) } } } // 把弹窗的异步回调转换成可等待的异步函数 private func askUserAboutAttendee(name: String) async -> Bool { return await withCheckedContinuation { continuation in let alert = UIAlertController(title: "参会确认", message: "\(name) 是否参加?", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .default) { _ in continuation.resume(returning: true) }) alert.addAction(UIAlertAction(title: "No", style: .cancel) { _ in continuation.resume(returning: false) }) present(alert, animated: true) } } }
方案关键点:
- 用
Task包裹异步逻辑,避免阻塞UI主线程 withCheckedContinuation将UIAlert的异步回调转换为可await的函数,让循环能暂停等待用户输入- 对字典进行排序,确保每次询问的顺序一致(字典本身是无序集合)
方案二:使用Completion Handler(兼容iOS 14及以下)
如果需要适配更早的系统,我们可以用递归的方式,每次处理完一个用户的输入后,再触发下一个成员的询问:
import Foundation import UIKit class AttendeeManager: UIViewController { var squad = [1:"Arsh", 2:"Arbab", 3:"Ayush", 4:"KC", 5:"Jaski", 6:"Gunny", 7:"Harsh", 8:"Nagib", 9:"Rithin", 10:"Gursh", 11:"Sonny"] var attendees = [String]() // 保存排序后的成员列表,方便递归遍历 private var sortedMembers: [String]! override func viewDidLoad() { super.viewDidLoad() // 转换为有序数组,固定询问顺序 sortedMembers = squad.sorted(by: { $0.key < $1.key }).map { $0.value } // 开始第一个成员的询问 askNextAttendee(at: 0) } private func askNextAttendee(at index: Int) { // 所有成员询问完毕,输出结果 guard index < sortedMembers.count else { print("最终参会名单:\(attendees)") return } let name = sortedMembers[index] let alert = UIAlertController(title: "参会确认", message: "\(name) 是否参加?", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .default) { [weak self] _ in self?.attendees.append(name) // 询问下一个成员 self?.askNextAttendee(at: index + 1) }) alert.addAction(UIAlertAction(title: "No", style: .cancel) { [weak self] _ in // 直接询问下一个成员 self?.askNextAttendee(at: index + 1) }) present(alert, animated: true) } }
方案关键点:
- 递归函数
askNextAttendee负责逐个处理成员,每次用户选择后触发下一次调用 - 使用
[weak self]避免循环引用,防止内存泄漏 - 提前将字典转换为有序数组,保证询问顺序稳定
额外:命令行工具版本(非UIKit场景)
如果是在Swift命令行工具中运行,不需要弹窗,直接通过控制台获取输入的话,代码会更简单——因为readLine()会同步阻塞线程,等待用户输入,循环会自然逐个处理:
import Foundation var squad = [1:"Arsh", 2:"Arbab", 3:"Ayush", 4:"KC", 5:"Jaski", 6:"Gunny", 7:"Harsh", 8:"Nagib", 9:"Rithin", 10:"Gursh", 11:"Sonny"] var attendees = [String]() // 按key排序遍历字典 for (_, name) in squad.sorted(by: { $0.key < $1.key }) { print("\(name) 是否参加?(Yes/No)") // 同步等待用户输入 guard let input = readLine()?.trimmingCharacters(in: .whitespacesAndNewlines) else { continue } if input.lowercased() == "yes" { attendees.append(name) } } print("最终参会名单:\(attendees)")
内容的提问来源于stack exchange,提问作者Arshveer Singh
相关产品推荐
相关产品推荐

