API Reference
June 16, 2026 ยท View on GitHub
Complete API reference for TLPhotoPicker.
Table of Contents
TLPHAsset
Wrapper around PHAsset with convenient helper methods.
Properties
public struct TLPHAsset {
// Underlying PHAsset
public var phAsset: PHAsset?
// Selection order (1-indexed)
public var selectedOrder: Int
// Asset type
public var type: AssetType // .photo, .video, .livePhoto
// Original file name
public var originalFileName: String?
// Indicates if asset was captured from camera
public var isSelectedFromCamera: Bool
// Full resolution image (sync, may be nil for iCloud)
public var fullResolutionImage: UIImage?
}
Asset Type
public enum AssetType {
case photo
case video
case livePhoto
}
Async Methods
fullResolutionImage() async
Get full resolution image using async/await (iOS 13+).
public func fullResolutionImage() async -> UIImage?
Example:
Task {
if let image = await asset.fullResolutionImage() {
await MainActor.run {
imageView.image = image
}
}
}
cloudImageDownload
Download image from iCloud with progress tracking.
@discardableResult
public func cloudImageDownload(
progressBlock: @escaping (Double) -> Void,
completionBlock: @escaping (UIImage?) -> Void
) -> PHImageRequestID?
Parameters:
progressBlock: Progress callback (0.0 to 1.0)completionBlock: Completion callback with image
Returns: Request ID for cancellation
Example:
asset.cloudImageDownload(
progressBlock: { progress in
print("Download: \(Int(progress * 100))%")
},
completionBlock: { image in
guard let image = image else { return }
self.imageView.image = image
}
)
File Export Methods
tempCopyMediaFile
Export original media file to temporary location.
@discardableResult
public func tempCopyMediaFile(
videoRequestOptions: PHVideoRequestOptions? = nil,
imageRequestOptions: PHImageRequestOptions? = nil,
livePhotoRequestOptions: PHLivePhotoRequestOptions? = nil,
exportPreset: String = AVAssetExportPresetHighestQuality,
convertLivePhotosToJPG: Bool = false,
progressBlock: ((Double) -> Void)? = nil,
completionBlock: @escaping ((URL, String) -> Void)
) -> PHImageRequestID?
Parameters:
videoRequestOptions: Options for video exportimageRequestOptions: Options for image exportlivePhotoRequestOptions: Options for Live Photo exportexportPreset: Video export quality presetconvertLivePhotosToJPG:false: Export Live Photo as.movfiletrue: Export Live Photo as.jpg/.heicstill image
progressBlock: Progress callbackcompletionBlock: Completion with file URL and MIME type
Returns: Request ID for cancellation
Example:
asset.tempCopyMediaFile(
convertLivePhotosToJPG: false,
progressBlock: { progress in
print("Export: \(Int(progress * 100))%")
},
completionBlock: { url, mimeType in
print("Exported to: \(url)")
print("MIME type: \(mimeType)")
// Use the file
self.uploadFile(at: url)
// Clean up temporary file
try? FileManager.default.removeItem(at: url)
}
)
Live Photo Export:
For complete Live Photo export, call twice:
// Export still image
asset.tempCopyMediaFile(convertLivePhotosToJPG: true) { imageURL, _ in
// Save image
}
// Export video component
asset.tempCopyMediaFile(convertLivePhotosToJPG: false) { videoURL, _ in
// Save video
}
exportVideoFile
Export video with custom options.
public func exportVideoFile(
options: PHVideoRequestOptions? = nil,
outputURL: URL? = nil,
outputFileType: AVFileType = .mov,
progressBlock: ((Double) -> Void)? = nil,
completionBlock: @escaping ((URL, String) -> Void)
)
Parameters:
options: Video request optionsoutputURL: Custom output path (optional)outputFileType: Export file type (.mov,.mp4, etc.)progressBlock: Progress callbackcompletionBlock: Completion with URL and MIME type
Example:
let outputURL = FileManager.default.temporaryDirectory
.appendingPathComponent("video.mp4")
asset.exportVideoFile(
outputURL: outputURL,
outputFileType: .mp4,
progressBlock: { progress in
print("Export: \(Int(progress * 100))%")
},
completionBlock: { url, mimeType in
print("Video exported to: \(url)")
}
)
Static Methods
asset(with:)
Fetch asset by local identifier.
public static func asset(with localIdentifier: String) -> TLPHAsset?
Parameters:
localIdentifier: PHAsset local identifier
Returns: TLPHAsset if found, nil otherwise
Example:
if let asset = TLPHAsset.asset(with: "some-local-identifier") {
print("Found asset: \(asset.originalFileName ?? "Unknown")")
}
File Size Methods
photoSize
Get photo file size.
public func photoSize(
options: PHImageRequestOptions? = nil,
completion: @escaping (Int) -> Void,
livePhotoVideoSize: Bool = false
)
Parameters:
options: Image request optionscompletion: Completion with size in byteslivePhotoVideoSize: Include Live Photo video size
Example:
asset.photoSize { bytes in
let mb = Double(bytes) / 1_048_576
print("Photo size: \(String(format: "%.2f", mb)) MB")
}
videoSize
Get video file size.
public func videoSize(
options: PHVideoRequestOptions? = nil,
completion: @escaping (Int) -> Void
)
Example:
asset.videoSize { bytes in
let mb = Double(bytes) / 1_048_576
print("Video size: \(String(format: "%.2f", mb)) MB")
}
TLPhotosPickerViewController
Main view controller for photo picking.
Initialization
public init()
public init(withPHAssets: (([PHAsset]) -> Void)?, didCancel: (() -> Void)?)
public init(withTLPHAssets: (([TLPHAsset]) -> Void)?, didCancel: (() -> Void)?)
Properties
// Configuration
public var configure: TLPhotosPickerConfigure
// Selected assets
public var selectedAssets: [TLPHAsset]
// Delegates
public weak var delegate: TLPhotosPickerViewControllerDelegate?
public weak var logDelegate: TLPhotosPickerLogDelegate?
// Custom data sources
public var customDataSouces: TLPhotopickerDataSourcesProtocol?
// Closures (alternative to delegate)
public var canSelectAsset: ((PHAsset) -> Bool)?
public var didExceedMaximumNumberOfSelection: ((TLPhotosPickerViewController) -> Void)?
public var handleNoAlbumPermissions: ((TLPhotosPickerViewController) -> Void)?
public var handleNoCameraPermissions: ((TLPhotosPickerViewController) -> Void)?
public var dismissCompletion: (() -> Void)?
public var didCaptureMediaURL: ((URL) -> Void)?
When set, camera captures are copied to a temporary file and returned through the callback. Captured media is not saved to the Photo Library, and the callback only runs when the copy succeeds. By the time the closure fires, the camera picker and TLPhotosPickerViewController have both been fully dismissed, so callers should only present their next screen and should not dismiss the picker themselves.
Methods
// UI customization (override in subclass)
open func makeUI()
// Dismissal
public func dismiss(animated: Bool, completion: (() -> Void)?)
TLPhotosPickerConfigure
Configuration object for the picker.
Builder Methods
// Grid layout
public func numberOfColumns(_ count: Int) -> Self
public func spacing(line: CGFloat, interitem: CGFloat) -> Self
// Selection
public func maxSelection(_ count: Int?) -> Self
public func singleSelection(_ enabled: Bool) -> Self
// Media types
public func allowVideo(_ allow: Bool) -> Self
public func allowLivePhotos(_ allow: Bool) -> Self
public func mediaType(_ type: PHAssetMediaType?) -> Self
// Camera
public func useCameraButton(_ use: Bool) -> Self
public func allowPhotograph(_ allow: Bool) -> Self
public func allowVideoRecording(_ allow: Bool) -> Self
public func recordingQuality(_ quality: UIImagePickerController.QualityType) -> Self
// Appearance
public func selectedColor(_ color: UIColor) -> Self
public func cameraBgColor(_ color: UIColor) -> Self
// Custom cells
public func photoCellNib(name: String, bundle: Bundle) -> Self
public func cameraCellNib(name: String, bundle: Bundle) -> Self
// Advanced
public func groupBy(_ grouping: PHFetchedResultGroupedBy?) -> Self
public func localizedTitles(_ titles: [String: String]) -> Self
Presets
public static var singlePhoto: TLPhotosPickerConfigure
public static var videoOnly: TLPhotosPickerConfigure
public static var photoOnly: TLPhotosPickerConfigure
public static var compactGrid: TLPhotosPickerConfigure
public static var largeGrid: TLPhotosPickerConfigure
Delegates
TLPhotosPickerViewControllerDelegate
public protocol TLPhotosPickerViewControllerDelegate: AnyObject {
func shouldDismissPhotoPicker(withTLPHAssets: [TLPHAsset]) -> Bool
func dismissPhotoPicker(withTLPHAssets: [TLPHAsset])
func dismissPhotoPicker(withPHAssets: [PHAsset])
func photoPickerDidCancel()
func dismissComplete()
func canSelectAsset(phAsset: PHAsset) -> Bool
func didExceedMaximumNumberOfSelection(picker: TLPhotosPickerViewController)
func handleNoAlbumPermissions(picker: TLPhotosPickerViewController)
func handleNoCameraPermissions(picker: TLPhotosPickerViewController)
}
All methods are optional (provide default empty implementations).
TLPhotosPickerLogDelegate
public protocol TLPhotosPickerLogDelegate: AnyObject {
func selectedCameraCell(picker: TLPhotosPickerViewController)
func deselectedPhoto(picker: TLPhotosPickerViewController, at: Int)
func selectedPhoto(picker: TLPhotosPickerViewController, at: Int)
func selectedAlbum(picker: TLPhotosPickerViewController, title: String, at: Int)
}
TLPhotopickerDataSourcesProtocol
public protocol TLPhotopickerDataSourcesProtocol {
func headerReferenceSize() -> CGSize
func footerReferenceSize() -> CGSize
func registerSupplementView(collectionView: UICollectionView)
func supplementIdentifier(kind: String) -> String
func configure(supplement view: UICollectionReusableView,
section: (title: String, assets: [TLPHAsset]))
}
Enumerations
PHFetchedResultGroupedBy
public enum PHFetchedResultGroupedBy {
case year
case month
case week
case day
case hour
case custom(dateFormat: String)
}
FetchCollectionType
public enum FetchCollectionType {
case assetCollections(PHAssetCollectionType)
case topLevelUserCollections
}
PopupConfigure
public enum PopupConfigure {
case animation(TimeInterval)
}
Helper Classes
Platform
public struct Platform {
public static var isSimulator: Bool
}
TLBundle
public class TLBundle {
class func bundle() -> Bundle
open class func podBundleImage(named: String) -> UIImage?
}
Related Documentation
- Configuration Guide - Configuration options
- Advanced Usage - Custom cells and delegates
- Migration Guide - Upgrading guide