Face detection and gallery loading for iOS. Scans photo library assets in batches, detects faces using Core Image, and exposes a list of assets that contain a face meeting a minimum size threshold. Suitable for building “photos with faces” or “selfie” galleries.
- iOS 14+
- Xcode 14+
- Swift 5.9+
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/serhatakalin/FaceGallery.git", from: "1.0.0")
]Or in Xcode: File → Add Package Dependencies and enter the repository URL.
Use PHPhotoLibrary.requestAuthorization(for:) (or requestAuthorization(for:access:) on iOS 14+) and handle .authorized / .limited / .denied as needed.
import FaceGallery
import Photos
// Smart albums: All Photos, Selfies, Favorites
let collections = AlbumLoader.loadAlbums(subTypes: [
.smartAlbumUserLibrary,
.smartAlbumSelfPortraits,
.smartAlbumFavorites
])
let allPhotos = collections.first { $0.assetCollectionSubtype == .smartAlbumUserLibrary }
let fetchResult = allPhotos.map { AlbumLoader.loadAssets(from: $0) }let state = FaceGalleryState()
let engine = FaceGalleryEngine(state: state, configuration: FaceGalleryConfiguration())
engine.fetchResults = fetchResult
engine.isLimitedPermission = (PHPhotoLibrary.authorizationStatus(for: .readWrite) == .limited)
engine.detect()state.$detectionState
.receive(on: DispatchQueue.main)
.sink { state in
switch state {
case .start: break // show loading
case .resume: break // append new batch to UI
case .finished: break // hide loading
case .photosChanged, .initial: break
}
}
.store(in: &cancellables)
state.$resultAssetsToDraw
.receive(on: DispatchQueue.main)
.sink { assets in
// Update collection view with assets
}
.store(in: &cancellables)When the user scrolls to the last cell, call:
engine.checkAssetsAreReady()This triggers the next batch of face detection; when it finishes, detectionState becomes .resume and resultAssetsToDraw is updated.
let loader = PhotoAssetLoader()
let size = CGSize(width: 200, height: 200)
let image = await loader.requestThumbnailAsync(for: asset, maxSize: size)
let fullSize = await loader.requestFullSizeImage(for: asset)| Type | Purpose |
|---|---|
FaceGalleryEngine |
Batch face detection over PHFetchResult<PHAsset>; drives state and cache |
FaceGalleryState |
@Published detectionState and resultAssetsToDraw |
DetectionState |
.initial, .start, .resume, .finished, .photosChanged |
FaceDetector |
Single-image face check with minimum size (CIDetector) |
FaceDetectionCache |
Persists per-asset results (optional UserDefaults) |
PhotoAssetLoader |
Thumbnail and full-size image loading via PHImageManager |
AlbumLoader |
Load smart albums and assets from PHAssetCollection |
FaceGalleryConfiguration |
Batch size, min face size, detector accuracy |
DeviceCapability |
Heuristics for legacy/small devices (batch size, accuracy) |
By default the cache uses UserDefaults key "FaceGallery.assetDict". You can pass a custom key or UserDefaults(suiteName:) when creating FaceDetectionCache to share or isolate cache with your app.
The Demo/FaceGalleryDemo Xcode project shows a single screen with a photo library permission flow and a collection view of assets that contain a face, using incremental loading.
See repository license file.