Complete API reference for TLPhotoPicker.
Wrapper around PHAsset with convenient helper methods.
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?
}public enum AssetType {
case photo
case video
case livePhoto
}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
}
}
}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
}
)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
}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)")
}
)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")")
}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")
}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")
}Main view controller for photo picking.
public init()
public init(withPHAssets: (([PHAsset]) -> Void)?, didCancel: (() -> Void)?)
public init(withTLPHAssets: (([TLPHAsset]) -> Void)?, didCancel: (() -> Void)?)// 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.
// UI customization (override in subclass)
open func makeUI()
// Dismissal
public func dismiss(animated: Bool, completion: (() -> Void)?)Configuration object for the picker.
// 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]) -> Selfpublic static var singlePhoto: TLPhotosPickerConfigure
public static var videoOnly: TLPhotosPickerConfigure
public static var photoOnly: TLPhotosPickerConfigure
public static var compactGrid: TLPhotosPickerConfigure
public static var largeGrid: TLPhotosPickerConfigurepublic 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).
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)
}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]))
}public enum PHFetchedResultGroupedBy {
case year
case month
case week
case day
case hour
case custom(dateFormat: String)
}public enum FetchCollectionType {
case assetCollections(PHAssetCollectionType)
case topLevelUserCollections
}public enum PopupConfigure {
case animation(TimeInterval)
}public struct Platform {
public static var isSimulator: Bool
}public class TLBundle {
class func bundle() -> Bundle
open class func podBundleImage(named: String) -> UIImage?
}- Configuration Guide - Configuration options
- Advanced Usage - Custom cells and delegates
- Migration Guide - Upgrading guide