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

Swift调用BTC.com API多区块数据时JSON解析崩溃求助

Hey there! Let's break down what's likely tripping up your getAllBlocks function when fetching multiple blocks from the BTC.com API.

The Core Issue: Mismatched Response Structure

My bet is that the API returns different JSON structures for single vs. multiple block requests:

  • When you request just latest, the response's data field is a single block object (like {"data": {...}}).
  • When you request latest,5000,2, the data field switches to an array of block objects (like {"data": [..., ...]}).

If your Swift parsing logic is only set up to handle a single block object, it'll crash when it encounters an array instead.

Common Fixes to Try

1. Update Your Codable Models to Handle Both Cases

If you're using Codable (the standard for Swift JSON parsing), you need a way to accept either a single block or an array of blocks. Here's a flexible approach with an enum:

// Define your basic Block model first
struct Block: Codable {
    // Add all your block properties here (e.g., height, hash, time)
    let height: Int
    let hash: String
    // ... other fields
}

// Create an enum to handle single/array responses
enum BlockResponseData: Codable {
    case single(Block)
    case multiple([Block])
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        // Try decoding as a single block first
        if let singleBlock = try? container.decode(Block.self) {
            self = .single(singleBlock)
        } 
        // If that fails, try decoding as an array
        else if let blockArray = try? container.decode([Block].self) {
            self = .multiple(blockArray)
        } 
        // If neither works, throw an error
        else {
            throw DecodingError.typeMismatch(
                BlockResponseData.self,
                DecodingError.Context(
                    codingPath: decoder.codingPath,
                    debugDescription: "Expected a single Block or array of Blocks"
                )
            )
        }
    }
    
    // Conform to Encodable (optional, if you need to send data back)
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .single(let block): try container.encode(block)
        case .multiple(let blocks): try container.encode(blocks)
        }
    }
}

// Wrap it in the top-level API response structure
struct APIResponse: Codable {
    let data: BlockResponseData
    // Include other API fields like status/message if needed
    let status: Int
    let message: String
}

2. Adjust Your Fetch Logic to Handle Both Response Types

Update your getAllBlocks function to use the new model and handle both cases gracefully:

func getAllBlocks(completion: @escaping (Result<[Block], Error>) -> Void) {
    let urlString = "https://chain.api.btc.com/v3/block/latest,5000,2"
    guard let url = URL(string: urlString) else {
        completion(.failure(NSError(domain: "Invalid URL", code: -1, userInfo: nil)))
        return
    }
    
    URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            completion(.failure(error))
            return
        }
        
        guard let data = data else {
            completion(.failure(NSError(domain: "No data received", code: -2, userInfo: nil)))
            return
        }
        
        // Print raw JSON to debug (remove in production)
        if let jsonString = String(data: data, encoding: .utf8) {
            print("API Response JSON: \(jsonString)")
        }
        
        do {
            let apiResponse = try JSONDecoder().decode(APIResponse.self, from: data)
            switch apiResponse.data {
            case .single(let block):
                completion(.success([block])) // Wrap single block in array for consistency
            case .multiple(let blocks):
                completion(.success(blocks))
            }
        } catch {
            print("Decoding failed with error: \(error)")
            completion(.failure(error))
        }
    }.resume()
}

3. Add Robust Error Handling

Never assume the API will return exactly what you expect. The print statements in the code above will help you see the raw JSON response, which is critical for debugging. If decoding fails, the error message will tell you exactly what part of the structure doesn't match your model.

Quick Debugging Tip

Before writing any code, send the two API requests (single vs. multiple blocks) in a tool like Postman or curl, and compare the JSON outputs. This will confirm whether the data field changes from an object to an array—this is almost certainly the root cause of your crash.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:00:58