Firebase Storage图片读取遇404错误及EXC_BAD_ACCESS异常的排查解决
Hey there! Let's break down exactly what's causing these issues and walk through how to fix them step by step:
Why You're Seeing These Problems
1. 404 Error (com.google.HTTPStatus domain)
This one's straightforward: the image path you're requesting from Firebase Storage doesn't exist. This aligns perfectly with your note that not all products have images—either the product never had an image uploaded, or you've got a typo in the storage path you're using to fetch it.
2. EXC_BAD_ACCESS Crash
This memory error almost always happens because of asynchronous code and collection view cell reuse. Here's the common scenario:
- You call
GetProductImagefor a cell - The cell gets reused (scrolled off screen) before the image fetch finishes
- When the completion block runs, it tries to update a cell that's already been deallocated or reassigned to a different index path
- This leads to accessing invalid memory, triggering the crash.
Step-by-Step Fixes
Fix 1: Handle Missing Images & 404 Errors Explicitly
Update your GetProductImage function to catch 404 errors and pass nil to the completion block—this lets you cleanly distinguish between "no image available" and other network issues:
public func GetProductImage(completion: @escaping ((UIImage?) -> Void)) { // Replace with your actual Firebase Storage reference path let storageRef = Storage.storage().reference(withPath: "your-product-image-path") storageRef.getData(maxSize: 10 * 1024 * 1024) { data, error in if let error = error { // Check for 404 status code to confirm missing image if let httpError = error as NSError?, httpError.code == 404 { completion(nil) return } // Log other errors (network issues, permission denied, etc.) print("Image fetch error: \(error.localizedDescription)") completion(nil) return } if let data = data, let image = UIImage(data: data) { completion(image) } else { completion(nil) } } }
Fix 2: Prevent EXC_BAD_ACCESS with Cell Reuse Safeguards
In your collectionView(_:cellForItemAt:) method, use weak references and index path checks to ensure you only update cells that are still associated with the original request:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellIdentifier", for: indexPath) as! YourCustomCell // Set a placeholder image immediately to avoid empty cells cell.productImageView.image = UIImage(named: "placeholder-no-image") // Fetch image with weak reference to avoid retaining deallocated cells GetProductImage { [weak cell] image in // Verify the cell is still linked to the original index path guard let currentCell = cell, collectionView.indexPath(for: currentCell) == indexPath else { return } currentCell.productImageView.image = image ?? UIImage(named: "placeholder-no-image") } return cell }
Bonus: Add a Missing Image Cache (Optional)
To avoid repeated 404 requests for products you already know don't have images, add a simple in-memory cache:
// Add this as a property in your view controller/data manager var missingProductImageIDs = Set<String>() // Update GetProductImage to accept a product ID and use the cache public func GetProductImage(forProductID id: String, completion: @escaping ((UIImage?) -> Void)) { // Skip fetch if we already know this product has no image if missingProductImageIDs.contains(id) { completion(nil) return } let storageRef = Storage.storage().reference(withPath: "products/\(id)/image.jpg") storageRef.getData(maxSize: 10 * 1024 * 1024) { [weak self] data, error in if let error = error as NSError?, error.code == 404 { self?.missingProductImageIDs.insert(id) completion(nil) return } // ... rest of your image handling code } }
内容的提问来源于stack exchange,提问作者Ofri

