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

Swift闭包内无法向数组追加对象问题求助

Fixing Your Empty scoresArray Issue in Swift Live Scores App

Hey there! Let's walk through why your scoresArray is staying empty even after your Alamofire request runs, and fix this step by step.

First, Let's Identify the Key Problems

  1. Asynchronous Request Timing
    Alamofire's network calls run in the background (asynchronously). If you try to check scoresArray right after calling getLiveScores in viewDidLoad, it will still be empty—because the request hasn't finished yet. The array only gets populated once the response comes back in the closure.

  2. Force Unwrapping Risks
    You're using ! to force-unwrap values everywhere (like JSON(response.result.value!) and string!). If any JSON field is missing, malformed, or of the wrong type, this will crash your app silently (or crash it outright), and the code that adds items to scoresArray will never run.

  3. Unpresented Error Alert
    When the request fails, you create an alert but never present it. You might think the request succeeded when it actually failed, leaving your array empty without knowing why.

  4. Missing UI Refresh
    Even if you populate the array, if you don't reload your table/collection view, you won't see the data (though you mentioned the array itself is empty, so this is secondary for now).


Step-by-Step Fixes

1. Fix the Network Request Closure

Update your getLiveScores method to handle success/failure safely, present errors, and avoid memory leaks with a weak self reference:

func getLiveScores(url : String) {
    Alamofire.request(url, method: .get).responseJSON { [weak self] response in
        guard let self = self else { return }
        
        switch response.result {
        case .success(let value):
            let liveScoresJSON = JSON(value)
            self.updateLiveScore(json: liveScoresJSON)
        case .failure(let error):
            let alert = UIAlertController(title: "Error Occurred", message: error.localizedDescription, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Ok", style: .cancel))
            // Actually present the alert so you know when requests fail
            self.present(alert, animated: true)
        }
    }
}

2. Safely Parse JSON Without Force Unwrapping

Rewrite updateLiveScore to use optional binding, handle missing fields, and clear old data before adding new results:

func updateLiveScore(json : JSON) {
    // Clear old data to avoid duplicate entries on repeated requests
    scoresArray.removeAll()
    
    // Check if the "result" field is actually an array
    guard let results = json["result"].array else {
        print("No valid results found in the JSON response")
        return
    }
    
    for result in results {
        let match = Score()
        // Use default values for missing fields instead of force-unwrapping
        match.homeTeamName = result["event_home_team"].string ?? "Unknown Home Team"
        match.visitorTeamName = result["event_away_team"].string ?? "Unknown Away Team"
        match.matchScore = result["event_final_result"].string ?? "0-0"
        match.matchTime = result["event_status"].string ?? "Unknown Status"
        
        scoresArray.append(match)
    }
    
    // Refresh your UI on the main thread (network calls run in background)
    DispatchQueue.main.async {
        // Replace with your table/collection view reference
        self.yourTableView.reloadData()
    }
}

3. Understand Asynchronous Flow

Remember: You can't access scoresArray immediately after calling getLiveScores. All code that relies on the array (like UI updates) must run after the updateLiveScore method finishes. That's why we put the reloadData() call inside updateLiveScore.

4. (Optional) Using inout for Array Parameters

If you want to pass the array as a parameter instead of using a class property, use Swift's inout keyword to modify the original array (instead of a copy):

func updateLiveScore(json : JSON, scoresArray: inout [Score]) {
    scoresArray.removeAll()
    
    guard let results = json["result"].array else {
        print("No valid results found")
        return
    }
    
    for result in results {
        let match = Score()
        match.homeTeamName = result["event_home_team"].string ?? "Unknown Home Team"
        // ... fill other properties ...
        scoresArray.append(match)
    }
}

Call it like this:

self.updateLiveScore(json: liveScoresJSON, scoresArray: &self.scoresArray)

Final Notes

  • Always avoid force-unwrapping (!) unless you're 100% certain the value exists—optional binding (if let/guard let) and default values (??) are much safer.
  • Network operations run on background threads, so all UI updates must happen on the main thread (hence DispatchQueue.main.async).
  • If your JSON structure doesn't match what you're expecting, use print(liveScoresJSON) to log the full response and verify the field names/paths.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:08:43