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'sdatafield is a single block object (like{"data": {...}}). - When you request
latest,5000,2, thedatafield 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

