iOS中如何快速获取手机全部图片并优化加载性能?
Hey there! I see exactly why your current code is dragging with 1000+ images—you’re loading every single photo synchronously upfront, which clogs up the main thread and wastes memory. Let’s fix this with practical, step-by-step optimizations:
The Core Issues in Your Current Code
- Synchronous Requests: Setting
requestOptions.isSynchronous = trueforces each image request to block until it finishes. With 1000 photos, this means your app freezes while processing one image at a time. - Preloading All Images: Storing every UIImage in an array immediately eats up tons of memory and delays any user interaction until all images are loaded.
Step-by-Speed Optimizations
1. Switch to Asynchronous Image Loading
First, ditch synchronous requests. Async loading lets the system handle multiple image requests in parallel without blocking the main thread. Update your request options for speed:
let requestOptions = PHImageRequestOptions() requestOptions.isSynchronous = false // Critical change requestOptions.resizeMode = .fast // Prioritize speed over pixel-perfect resizing requestOptions.deliveryMode = .fastFormat // Get a quick preview first (optional: load high-res later) requestOptions.isNetworkAccessAllowed = true // Include iCloud photos if needed
2. Load Images On-Demand (Not All At Once)
Instead of preloading every image into an array, store the PHAsset objects first, then load images only when they’re visible in your collection view. This cuts initial load time drastically.
First, fetch and store the assets:
func getAllPhotoAssets() -> [PHAsset] { let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)] let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) var assets = [PHAsset]() fetchResult.enumerateObjects { asset, _, _ in assets.append(asset) } return assets }
Then, load images only when cells appear in your collection view:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell let asset = yourAssetArray[indexPath.item] // Cancel any stale request for this cell to avoid wrong images PHImageManager.default().cancelImageRequest(cell.imageRequestID) // Request the image asynchronously cell.imageRequestID = PHImageManager.default().requestImage( for: asset, targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions ) { [weak cell] image, info in guard let cell = cell else { return } cell.photoImageView.image = image } // Set selection state (track selected assets in a separate array) cell.isSelected = yourSelectedAssets.contains(asset) return cell }
3. Add Request Cancellation
Make sure your custom cell can cancel old requests when reused, so you don’t waste resources on images that are no longer visible:
class PhotoCell: UICollectionViewCell { @IBOutlet weak var photoImageView: UIImageView! var imageRequestID: PHImageRequestID? = nil override func prepareForReuse() { super.prepareForReuse() photoImageView.image = nil // Clear old image if let requestID = imageRequestID { PHImageManager.default().cancelImageRequest(requestID) } } }
4. Optional: Boost Performance with Image Caching
Use PHCachingImageManager instead of the default manager to automatically cache loaded images. Scrolling back to previously seen cells will be instant:
let cachingImageManager = PHCachingImageManager() // Enable caching in viewDidLoad override func viewDidLoad() { super.viewDidLoad() cachingImageManager.startCachingImages( for: yourAssetArray, targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions ) } // Stop caching when the view disappears to free memory override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) cachingImageManager.stopCachingImages( for: yourAssetArray, targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions ) }
Why This Works
- Async loading lets the system handle multiple requests in parallel, so your app stays responsive.
- On-demand loading means you only load images the user can see right away, cutting initial load time from seconds to milliseconds.
- Cancellation and caching eliminate wasted work and make scrolling smooth even with thousands of photos.
内容的提问来源于stack exchange,提问作者Gaurav Gupta

