Modular iOS Photo Album Architecture and Implementation
The article describes a modular iOS photo‑album solution that isolates the album as an independent, reusable SDK through a three‑layer architecture—interface, view‑customization, and logic management—implementing reading and change chains, handling iOS 14 privacy, iCloud assets, and multithreaded PhotoKit operations to reduce coupling and maintenance costs.
Background and Challenges – The "拍立淘" photo album has been used for years across multiple business scenarios (e.g., Taobao, Scan, AR). As features accumulated, the module became tightly coupled with business code, lacked clear layering, and suffered from high maintenance cost, UI inconsistencies, and iOS 14 limited‑photo‑library issues.
Design Goals – 1) Expose the album as an independent capability that can be reused by other modules. 2) Decouple the album from business code and optionally provide it as an SDK. 3) Support unified UI, iPhone X/iPhone 14‑series notch adaptation, and consistent spacing.
Layered Architecture – The solution follows a three‑layer design:
Interface Layer – external API/adapter (adapter pattern) that business teams implement.
View‑Customization Layer – MVVM architecture separating Model, ViewModel, and View.
Logic Management Layer – further split into Reading Chain, Change Chain, and Experience‑Optimization Chain.
Reading Chain – Handles system album fetching, asset querying, model conversion, and media loading. Example implementation:
- (NSArray<PhotoGroupModel *> *)fetchAssetGroup {
// …
// read system album data
self.lastResult = assetGroups.lastObject.fetchResult;
[self startObserver];
// …
}
- (void)startObserver {
[self.observer initCursor:self.lastResult];
[self.observer startObserver];
}
- (void)stopObserver {
[self.observer stopObserver];
}Change Chain – Uses PhotoKit change observer to refresh UI when the system album changes. The observer registration is performed on a dedicated queue to avoid duplicate registration:
- (void)startObserver {
dispatch_async(self.observerQueue, ^{
if (!self.isObserving) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
self.isObserving = YES;
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
}
});
}
- (void)stopObserver {
dispatch_async(self.observerQueue, ^{
if (self.isObserving) {
self.isObserving = NO;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
}
});
}The callback method is:
- (void)photoLibraryDidChange:(PHChange *)changeInstance { /* update data and refresh UI */ }Privacy & iOS 14 Limited Access – The module checks photo‑library permission before any read operation. When the user grants limited access, the code detects the mode and guides the user to grant full access if needed. All read actions are timed to avoid unnecessary privacy‑report entries.
iCloud Support – Thumbnail images are loaded first; full‑size images are fetched on demand. The implementation respects assets stored in iCloud and uses PHImageManager to request high‑resolution data only when required.
Multithreading Considerations – All PhotoKit operations are confined to a dedicated serial queue. When the main thread accesses PHPhotoLibrary, loading is blocked to prevent ANR caused by os_unfair_lock_lock contention.
External API – The album exposes flexible callbacks using dictionaries and block types, e.g.:
typedef void (^imagePickerFinishOpenBlock)(NSDictionary *mediaInfo, NSDictionary *paramURLArgs);
typedef void (^imagePickerCancelBlock)(void);
- (void)openImagePickerViewController:(imagePickerFinishOpenBlock)getImageBlock cancelBlock:(imagePickerCancelBlock)cancelBlock;
- (void)openImagePickerViewControllerWithConfig:(PhotoConfig *)photoConfig finishBlock:(imagePickerFinishOpenBlock)getImageBlock cancelBlock:(imagePickerCancelBlock)cancelBlock;
- (void)requestAuthAndOpenImagePickerViewControllerWithConfig:(PhotoConfig *)photoConfig finishBlock:(imagePickerFinishOpenBlock)getImageBlock cancelBlock:(imagePickerCancelBlock)cancelBlock;
- (void)dismissImagePickerAnimated:(BOOL)flag completion:(void (^)(void))completion;Summary – By refactoring the photo album into a clean, layered, and modular architecture, coupling with business code is eliminated, maintenance cost is reduced, and the module can be reused across multiple products. Future work includes optimizing loading performance for massive data sets.
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.