TZImagePickerController: a multi-select photo and video picker for UIKit apps
一个支持多选、选原图和视频的图片选择器,同时有预览、裁剪功能,支持iOS6+。 A clone of UIImagePickerController, support picking multiple photos、original photo、video, also allow preview photo and video, support iOS6+
At a glance
- What is it?
- TZImagePickerController is an Objective-C replacement for UIImagePickerController that adds multi-select, original-photo and video picking, and preview. It suits apps still built on UIKit and the Photos framework, and it is the wrong tool for SwiftUI-first projects.
- Who is it for?
- Adopt TZImagePickerController if you have a UIKit app that needs multi-select, original-photo or video picking and you are willing to read the demo and the FAQ before filing an issue. Do not adopt it if your UI is SwiftUI-first, or if you need an actively released library: the most recent release listed is 3.4.3 from 2020-09-24, even though the last push to master was on 2026-08-15.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 47 days ago.
- What is it written in?
- Mainly Objective-C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What TZImagePickerController replaces, and who it is for
UIImagePickerController gives you a system sheet that returns one photo or one video. TZImagePickerController is described in its README as "a clone of UIImagePickerController" that adds multi-select, an original-photo option and video picking, plus preview screens. That gap is the whole reason the library exists. Apps that let a user attach several pictures to a post, a listing or a message end up writing their own grid over the Photos framework, and this project is one such grid that already exists.
The audience is narrow and identifiable. The code is Objective-C, the integration paths are CocoaPods, Carthage and manual drag-in, and the README's example uses alloc/initWithMaxImagesCount:delegate: and presentViewController:. If your app is UIKit and you are comfortable in Objective-C or in a mixed project, the shape of the API will be familiar. If your app is SwiftUI-first, or if you have no intention of touching the Photos framework directly, this is a dependency you will fight rather than use. The README's requirements section states iOS 10 or later, while the repository description says iOS6+; the README is the more recent statement, and it is the one to trust when you set a deployment target.
How the picker is wired: delegate or block, assets in, UIImage out
The mechanism is a view controller you present yourself. You construct a TZImagePickerController with a maximum image count and a delegate, optionally attach a completion block, and present it. The picker owns the album list, the photo grid, the selection state and the preview screens; your code owns what happens after the user confirms.
The result arrives two ways, and the README says they are equivalent: a delegate callback, or a block set with setDidFinishPickingPhotosHandle:. The block signature carries three things: an NSArray of UIImage objects, an NSArray of assets, and a BOOL that reports whether the user chose the original photo. That third value matters, because the README's FAQ addresses it directly: the photos array is not the original image, and the FAQ points to issue 457 for how to obtain the original rather than restating the method.
The asset array is the interesting half. The README is blunt that a file path is not a route to the library: in the FAQ about PHImageFileURLKey, it says not to reach for that key and that photos can only be accessed through the Photos framework. If you need a path to upload from, the documented approach is to write the UIImage into the sandbox and use that sandbox path. This is a design constraint, not an oversight. It means the picker hands you an in-memory image and an asset reference, and any upload pipeline that expects a file URL has to be adapted on your side.
Installing TZImagePickerController with CocoaPods, Carthage or by hand
CocoaPods is the shortest path, and the podspec ships two variants. The full version includes the location code; the Basic subspec omits it. If your app never asks for location, the Basic subspec is the one to pick, and the release notes for 3.8.4 record that the no-location version was added deliberately.
pod 'TZImagePickerController' # full version
pod 'TZImagePickerController/Basic' # no location codeCarthage users add a single line to the Cartfile. The README also documents manual installation: drag the TZImagePickerController folder into the project and import the header.
github "banchichen/TZImagePickerController"A first real use is three statements. Allocate the picker with a maximum count and a delegate, set the block that receives the result, and present it. The README gives exactly this example, and it is worth copying verbatim before you customize anything.
TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self];
[imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
}];
[self presentViewController:imagePickerVc animated:YES completion:nil];Before any of that runs, the Info.plist needs the privacy keys the README lists, because the library touches the camera, location, microphone and photo library. The README points at the demo's Info.plist for the exact set: Privacy - Camera Usage Description, Privacy - Location Usage Description, Privacy - Location When In Use Usage Description, Privacy - Microphone Usage Description, Privacy - Photo Library Usage Description, and Prevent limited photos access alert. Copy them from the demo rather than guessing which ones your build actually needs. The release notes for 3.8.5 also record that a privacy manifest file was added, which matters if you ship through App Store review that inspects manifests.
Where the picker gets in your way
The filtering hooks are synchronous, and the README is unusually candid about the consequence. If you want to hide assets that fail your own rules, you implement isAssetCanBeDisplayed and return the asset; the library leaves the display decision to you. But the FAQ states that a synchronous method cannot filter on information that requires an asynchronous fetch, such as a video's size or whether it lives in iCloud. To do that, the README says, you would have to modify the source, and the album would open more slowly. A second hook, isAssetCanBeSelected, fires at selection time instead, which lets you show the asset and reject it when the user taps. That is a real trade-off between a fast grid and a strict one, and the library pushes the choice onto you.
Video export is the other soft spot. The FAQ splits it into two steps: obtaining an AVURLAsset from the PHAsset, then writing it into the sandbox. The first step is the problem, because an iCloud video involves a network request and the README says that timing is effectively uncontrollable. The suggested remedy is to copy the source and surface your own progress indicator. There is also a history of orientation fixes: the FAQ notes that from 2.2.6 the library stopped correcting video orientation by default, that needFixComposition can turn correction back on, and that enabling it can break export of video recorded on Android.
Navigation-bar conflicts deserve a mention because they are the most common integration complaint in the FAQ. If you use WRNavigationBar, the README says to add the TZImagePickerController controllers to its blacklist; if you use GKNavigationBarViewController, the FAQ requires version 2.0.4 or later. From 3.6.4 onward, setting the bar color also requires standardAppearance configuration, as shown in the demo.
TZImagePickerController compared with PHPickerViewController
The honest alternative is Apple's own PHPickerViewController, introduced with iOS 14. The difference is architectural rather than cosmetic. PHPicker runs out of process: the system presents it, and your app receives item providers it must load, which means the picker never holds your library access in the same way. TZImagePickerController is in-process and built on the Photos framework, so it can offer hooks like isAssetCanBeDisplayed and isAssetCanBeSelected, and it can implement its own preview and cropping screens.
That control is the reason to choose it, and the reason not to. If you need per-asset filtering rules, a custom preview flow, or video trimming inside the picker (allowEditVideo was added in 3.6.2 for single-video selection), the in-process model gives you the seams to do it. If you just need the user to hand you a few photos and you support iOS 14 and later, PHPicker is less code and fewer privacy keys, and the README's own list of required Info.plist entries shows how much surface the in-process approach adds. Note also that the project's release cadence has slowed: the most recent release listed is 3.4.3, dated 2020-09-24, while newer work appears in the release notes as 3.8.x entries. The README documents no rollback path and no deprecation policy.
Maintenance, licence and what an upgrade costs
The repository is not archived, and the last push to master was on 2026-08-15. The release list, however, ends at 3.4.3 from 2020-09-24, while the release-notes section of the README describes 3.8.5 and 3.8.8. That mismatch is worth understanding before you pin a version: the changelog is richer than the release feed, so read the README's release-notes section rather than trusting the release list alone. The README states that 3.8.8 supports iOS 18 and fixes an openURL failure, and that 3.8.5 added a privacy manifest.
The licence is MIT, which is permissive and places few conditions on commercial use; the repository carries a LICENSE file at the top level. Nothing here is legal advice, and if your organisation has a policy on bundled third-party code, the MIT text is short enough to review directly. The practical upgrade cost is integration drift, not API churn. The FAQ entries about navigation-bar libraries, the standardAppearance requirement from 3.6.4, and the needFixComposition flag all describe changes that require you to revisit your own wrapper code, not just bump a pod version. Budget for that whenever you move across a minor version.
Editorial conclusion
Adopt TZImagePickerController if you have a UIKit app that needs multi-select, original-photo or video picking and you are willing to read the demo and the FAQ before filing an issue. Do not adopt it if your UI is SwiftUI-first, or if you need an actively released library: the most recent release listed is 3.4.3 from 2020-09-24, even though the last push to master was on 2026-08-15. Verify first that your target iOS version is covered, that the privacy keys and the privacy manifest are in place, and that the limited-photo-library flow behaves on a real device, since the README notes a simulator bug in that mode.
Frequently asked questions
How do I install TZImagePickerController?
Add pod 'TZImagePickerController' for the full version or pod 'TZImagePickerController/Basic' if you do not want the location code, or use the Carthage line github "banchichen/TZImagePickerController". The README also documents dragging the TZImagePickerController folder into the project and importing its header.
Which iOS versions does TZImagePickerController support?
The README's requirements section states iOS 10 or later, and the release notes record iOS 18 support in 3.8.8. The repository description says iOS6+, which conflicts with the README and should not be used to set a deployment target.
Why is the image in the photos array not the original photo?
The README's FAQ says the returned images are not originals and points to issue 457 for the explanation, rather than restating the method. The completion block also reports whether the user selected the original photo, so you can branch on that flag.
Why can I not get a file path for a photo with TZImagePickerController?
The FAQ states that PHImageFileURLKey is not usable and that photos can only be accessed through the Photos framework. If you need a path for uploading, save the UIImage to the sandbox first and use that sandbox path, and use the photo's name directly if your upload needs a name parameter.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/banchichen-tzimagepickercontroller)