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

如何将闭包中的变量移至其他函数?iOS用户数据迁移需求

Got it, let's break down how to solve this. Your goal is to replace the hardcoded user array in generateUsersData() with data fetched asynchronously from usernameList() and idList()—here's a step-by-step solution that works with async network calls:

Step 1: Update UsersData.generateUsersData() for async data fetching

Since usernameList() and idList() are async (they use completion closures), we can't just return an array directly. Instead, we'll modify generateUsersData() to take its own completion handler, use a DispatchGroup to wait for both API calls to finish, then assemble the User array.

import Foundation

// Assume your User model looks like this (adjust if needed)
struct User {
    let id: String
    let username: String
}

final class UsersData {
    static func generateUsersData(completion: @escaping ([User]?, Error?) -> Void) {
        let dispatchGroup = DispatchGroup()
        
        var fetchedUsernames: [String]?
        var fetchedIds: [String]?
        var requestError: Error?
        
        // Fetch usernames
        dispatchGroup.enter()
        usernameList { inputArray, error in
            defer { dispatchGroup.leave() }
            if let error = error {
                requestError = error
                return
            }
            fetchedUsernames = inputArray
        }
        
        // Fetch IDs
        dispatchGroup.enter()
        idList { idArray, error in
            defer { dispatchGroup.leave() }
            if let error = error {
                requestError = error
                return
            }
            fetchedIds = idArray
        }
        
        // Wait for both requests to complete, then process data
        dispatchGroup.notify(queue: .main) {
            // Handle any request errors first
            if let error = requestError {
                completion(nil, error)
                return
            }
            
            // Make sure we have matching counts of usernames and IDs
            guard let usernames = fetchedUsernames,
                  let ids = fetchedIds,
                  usernames.count == ids.count else {
                let mismatchError = NSError(
                    domain: "UsersDataError",
                    code: 0,
                    userInfo: [NSLocalizedDescriptionKey: "Usernames and IDs count don't match"]
                )
                completion(nil, mismatchError)
                return
            }
            
            // Zip IDs and usernames into User objects
            let users = zip(ids, usernames).map { User(id: $0.0, username: $0.1) }
            completion(users, nil)
        }
    }
    
    // Stub for your existing usernameList function (adjust signature if needed)
    private static func usernameList(completion: ([String], Error?) -> Void) {
        // Your actual network request logic here
        completion(["Bill@comcast.net", "Oscar Peterson@yahoo.com", "DaveBrubeck@gmail.com"], nil)
    }
    
    // Stub for your existing idList function (adjust signature if needed)
    private static func idList(completion: ([String], Error?) -> Void) {
        // Your actual network request logic here
        completion(["111", "222", "333"], nil)
    }
}

Step 2: Integrate with your TableViewController

Now, in your TableViewController, you'll call the updated generateUsersData() method, update your data source, and reload the table once the data is ready:

import UIKit

class TableViewController: UITableViewController {
    private var users: [User] = []
    private let cellIdentifier = "UserCell"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
        fetchUsers()
    }
    
    private func fetchUsers() {
        UsersData.generateUsersData { [weak self] users, error in
            guard let self = self else { return }
            
            if let error = error {
                // Handle error (e.g., show an alert to the user)
                print("Failed to load users: \(error.localizedDescription)")
                return
            }
            
            if let fetchedUsers = users {
                self.users = fetchedUsers
                self.tableView.reloadData()
            }
        }
    }
    
    // MARK: - Table view data source
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        users.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
        let user = users[indexPath.row]
        cell.textLabel?.text = user.username
        cell.detailTextLabel?.text = user.id
        return cell
    }
}

Key Things to Remember

  • Async Completion Handlers: We use a completion handler because network requests don't block the main thread—we have to wait for them to finish before processing the data.
  • DispatchGroup: This ensures we don't try to create User objects until both the username and ID lists are fully fetched.
  • Error Handling: We catch network errors and also handle cases where the number of usernames doesn't match the number of IDs (to avoid crashes).
  • Weak Self: Using [weak self] in the completion handler prevents memory leaks by breaking the retain cycle between the view controller and the async closure.

内容的提问来源于stack exchange,提问作者X 1 go

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:32:12