I. Overview
This article then explains the picture framework of IOS development, focusing on the photokit and its differences with alassetlibrary, and how to encapsulate a common approach based on Photokit and Alassetlibrary.
Here is an introduction to the basic composition of photokit in the previous article:
- Phasset: Represents a resource in photo gallery, similar to Alasset, where resources can be obtained and saved through Phasset
- Phfetchoptions: The parameter to get the resource, can pass nil, even with the system default value
- A subclass of Phassetcollection:phcollection that represents an album or a moment, or a "smart album" (a specific series of albums provided by the system, such as: recently deleted, video list, favorites, etc., as shown)
- Phfetchresult: Represents a collection of resource results, or a collection of albums, obtained from the Phcollection class method
- Phimagemanager: Used to handle the loading of resources, the process of loading pictures with cache processing, you can pass in a phimagerequestoptions control the output size of the resource and other specifications
- Phimagerequestoptions: As mentioned above, control a series of parameters when loading a picture
There is also an additional concept phcollectionlist, which represents a set of phcollection, which is itself a phcollection, so phcollection as a collection can contain other collections, which enables the The composition of Photokit is more complicated than the alassetlibrary. Also similar to Alassetlibrary, a phasset can belong to many different phassetcollection at the same time, the most common example is the photos just taken, at least also belong to the "recently added", "Camera roll" and "photos – select" These three Phassetcollection. The relationship between these concepts is as follows:
Two. Mechanism of Photokit 1. Get Resources
Getting data in alassetlibrary, whether it's an album or a resource, is essentially using enumerations to traverse the photo gallery to get the data, and the data is from the Alassetlibrary (Photo gallery) –alassetgroup (album)- Alasset (resources) This path by layer, even if there is directly from the alassetlibrary layer to obtain Alasset interface, is essentially an enumeration alassetlibrary, not directly obtained, the benefits are obvious, is very consistent with the display path for resources in real-world applications: Photo Gallery – Photo Gallery – pictures or videos, but it's inefficient and inflexible to get resources in an enumeration way.
In Photokit, it is the use of "get" the way to pull resources, these acquisition means, are a series of shapes such as class Func fetchxxx (..., options:phfetchoptions), Phfetchresult class method, Which class method to use, depending on whether you need to get a photo album, a time or a resource, the option in this kind of method acts as a filter, you can filter the type of album, date, name, etc., so that the corresponding resources are directly obtained without the need for enumeration. For example, there are a few small examples in the previous article:
12345678910 |
// 列出所有相册智能相册
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:
nil
];
// 列出所有用户创建的相册
PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:
nil
];
// 获取所有资源的集合,并按资源的创建时间排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[
NSSortDescriptor
sortDescriptorWithKey:
@"creationDate"
ascending:
YES
]];
PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
|
As mentioned earlier, the acquisition from Phassetcollection can be an album or a resource, but regardless of what kind of content, all unified use Phfetchresult object encapsulation, so although phassetcollection The results obtained may be varied, but the phfetchresult can be used to process the content (that is, traversing Phfetchresult) using a unified approach. For example, extend the above example:
123456789101112131415161718192021222324 |
// 列出所有相册智能相册
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:
nil
];
// 这时 smartAlbums 中保存的应该是各个智能相册对应的 PHAssetCollection
for
(
NSInteger
i = 0; i < fetchResult.count; i++) {
// 获取一个相册(PHAssetCollection)
PHCollection *collection = fetchResult[i];
if
([collection isKindOfClass:[PHAssetCollection
class
]]) {
PHAssetCollection *assetCollection = (PHAssetCollection *)collection;
// 从每一个智能相册中获取到的 PHFetchResult 中包含的才是真正的资源(PHAsset)
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:fetchOptions];
else
{
NSAssert
(
NO
,
@"Fetch collection not PHCollection: %@"
, collection);
}
}
// 获取所有资源的集合,并按资源的创建时间排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[
NSSortDescriptor
sortDescriptorWithKey:
@"creationDate"
ascending:
YES
]];
PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
// 这时 assetsFetchResults 中包含的,应该就是各个资源(PHAsset)
for
(
NSInteger i = 0; i < fetchResult.count; i++) {
// 获取一个资源(PHAsset)
PHAsset *asset = fetchResult[i];
}
|
2. How to get images and pit points
Through the above steps, you can already see how to get the phasset representing the resource in Photokit, but unlike Alassetlibrary, which takes the image directly from Alasset, Photokit cannot get the diagram directly from the Phasset instance. Like, instead of introducing a manager Phimagemanager get the image. Phimagemanager is a request to pull the image, and can control the size of the requested image, clipping method, quality, caching and the management of the request itself (make a request, cancel the request), etc. The method of requesting an image is an instance of Phimagemanager:
12345 |
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset
targetSize:(CGSize)targetSize
contentMode:(PHImageContentMode)contentMode
options:(nullable PHImageRequestOptions *)options
resultHandler:(
void
(^)(UIImage *__nullable result,
NSDictionary
*__nullable info))resultHandler;
|
The parameters of this method pits a lot of points, the following parameters to enumerate its role and pit point:
- Asset, the image corresponds to the phasset.
- Targetsize, the size of the image that needs to be acquired, if the input size is larger than the size of the resource's original, only the original is returned. It is important to note that, for Phimagemanager, all dimensions are Pixel as units (note that all sizes is in pixels), so in order to obtain the correct size of the image, you need to convert the input size to Pixel. If you need to return the original size, you can pass in the pre-defined constant phimagemanagermaximumsize in Photokit, which means that the largest size in the optional range is returned, the original size.
- Contentmode, the image is clipped in a way that is similar to the UIView Contentmode parameter, and controls whether the photo should be placed in the final display container in a proportional or proportional manner. Note If Targetsize is passed into Phimagemanagermaximumsize, Contentmode will be treated as phimagecontentmodedefault regardless of the value passed in.
- Options, a phimagerequestoptions instance, can control the content is quite rich, including the image quality, version, there will be parameters to control the image clipping, and then expand the description.
- Resulthandler, the block that is called after the request is completed, returns a UIImage containing the resource for the image and a nsdictionary that contains the image information, which may be called multiple times during the entire request period. This is illustrated with the options parameter below.
(1) phimagerequestoptions and ICloud photo Gallery
The phimagerequestoptions contains a series of properties that control the requested image.
The ResizeMode property controls the clipping of the image, and does not know why Photokit in the request image method (Requestimageforasset) already has parameters that control the image clipping (Contentmode), and the options Controls the clipping property, but if there is a conflict between the clipping results that are controlled in two places, the Photokit will be based on the results of the resizemode. In addition, ResizeMode also has the effect of controlling image quality. If ResizeMode is set to Phimagerequestoptionsresizemodeexact, the returned image must match the target size, and the image quality is also high-quality image, and set to The phimagerequestoptionsresizemodefast request is more efficient, but the returned image may not be the same as the target size and the quality is lower.
In Photokit, there is good support for icloud Photo Gallery, if the user opens icloud photo gallery and chooses "Optimize Iphone/ipad storage", or "Download and keep original" but the original is not loaded, Photokit The phasset of these non-native images are also available in advance, but since there is no original image locally, Photokit will attempt to download the image from ICloud if a request for a high definition image is generated, and the final performance of this behavior will be phimagerequestoptions Is affected by the value in the. Some of the properties that are often used in Phimagerequestoptions are as follows:
The networkaccessallowed parameter controls whether network requests are allowed, defaults to no, and if no network requests are allowed, then no, and of course, no iCloud image originals are pulled. The DeliveryMode is used to control the picture quality of the request. The synchronous control is a synchronous request, the default is NO, and if synchronous is YES, which is the synchronization request, DeliveryMode is considered Phimagerequestoptionsdeliverymodehighqualityformat, which automatically returns high-quality images, is not recommended for synchronous requests, otherwise the response time will be long if the interface needs to wait for the returned image to respond further.
There is also an attribute progresshandler that is closely related to icloud, which is automatically called when the image needs to be downloaded from icloud, and the block returns the progress of the image download, the image information, and the error message. Developers can use this information to feed back to the user the current image of the download progress and status, but note that Progresshandler is not executed on the main thread, so in which need to manipulate the UI, you need to manually put into the main thread execution.
As mentioned above, the parameter Resulthandler in Requestimageforasset may be called multiple times, which is what the image needs to be downloaded from ICloud. In the content returned by Requestimageforasset, a small version of the image is returned from the first request, and when the HD image is still being downloaded, the developer can first show the user the low-clear version of the image, and the block will eventually return to the high-definition artwork after multiple calls. As to which version of the image is currently returned, it can be learned in Nsdictionary info returned by block that Phimageresultisdegradedkey indicates that the currently returned UIImage is a low-clear image. If you need to determine whether you have obtained a high-definition image, you can judge:
12 |
// 排除取消,错误,低清图三种情况,即已经获取到了高清图 BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]; |
In addition, when we use Requestimageforasset to make requests for images, if an image request is made to the same resource simultaneously in the same phimagemanager, the progress of the request can be shared, so we can use this feature to Phimagemanager is used in a single case, so there is no need to worry about the download progress of the image when switching the interface. For example, in the Image list page triggered the download image, when we left the list page into the preview of the big picture interface, do not have to worry about re-image will be re-downloaded, as long as no manual removal of image download, into the preview of the large image screen download will automatically continue to download the image from the last progress.
If you want to cancel the download of the image, you can use the Cancelimagerequest method of the Phimagemanager, which passes in the request ID of the request image, which can be obtained from the Requestimageforasset return value. It can also be obtained from Nsdictionary info, which contains the image information mentioned earlier, as long as the Phimagemanager that received the cancellation request is the same instance as the Phimagemanager that just made the request. Using a singleton as described above is the simplest and most effective way.
Finally, we also introduce a Phimagerequestoptions property versions, which refers to whether the captured image needs to contain information (such as filters, rotations, etc.) processed by the system album "Edit" function, which is much more flexible than alassetlibrary. The alassetlibrary does not have the flexibility to control whether the captured image has an "edited" effect, such as an interface in Alasset to get the original image, Fullresolutionimage gets a picture without an "edit" effect, to get an "edit" Effect of the image, only self-processing to get these filter effects, and manually superimposed up. In our UI framework Qmui the acquisition of the original image to make such a package, the whole process is more cumbersome, and the framework of the process Photokit part of the flexibility, which also reflects the photokit compared to the main features of alassetlibrary-complex but flexible. The third part of the article will also detail how to deal with this problem.
(2) Optimization of image Acquisition
Phimagemanager provides a subclass of Phimagecachingmanager to handle the cache of images, but this subclass is more useful than just the cache of the image itself-the cache that handles the entire loading process of the image. For example, to display thumbnails of a large number of resource images such as image lists on a collectionview, you can use Phimagecachingmanager to pre-load some images into memory, which is useful for optimizing the performance of CollectionView scrolling. However, this is only official, in fact, because the process of loading images is not certain, the actual requirements of each business load image may be different, so Phimagecachingmanager also use a relatively loose way to control these caches, the key method:
1 |
- ( void )startCachingImagesForAssets:( NSArray <PHAsset *> *)assets targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options; |
Need to pass in a set of Phasset, as well as Targetsize,contentmode, as well as a phimagerequestoptions, as described above, which have a reciprocal effect between these parameters, So, in fact, different scenarios are not the same for each parameter, and the best values for these parameters can only be tested in the scene. so, rather than using Phimagecachingmanager, I've summed up some of the more simple and workable caching methods:
- Get the picture as far as possible to obtain a preview, do not directly display the original, it is recommended to get the same size as the device screen image can be, in fact, the system album preview of the large image is also used in the preview, which is the system album loading speed reasons.
- Get the picture using an asynchronous request, as described above, when the request is asynchronous when the block of the returned image is called multiple times, a low-clear image is returned, and a high-definition image is returned, which can greatly reduce the waiting time of the UI.
- Get to the high-definition map can be cached, simply use the variable cache, as far as possible after the acquisition of high-definition graphics to avoid re-initiating requests to obtain images. Because even though the original image has been downloaded, it may take some time for the system to generate the image and crop the image because the picture is larger in size when it is re-requested.
- Pre-loading images, such as a preview of a larger image, will only see a large image, so it is helpful to speed up the response of the UI by asking for a picture in advance to request its proximity to two photos.
After the actual test, if the request is a thumbnail (that is, small size image), even if the requested image is many, still does not produce any non-smooth performance, but if the request is a large HD, then even if only a few pictures at the same time will produce a fluid situation. As mentioned above, the appearance of these conditions is likely to be that the image is generated from the picture metadata when the large image is requested, and the process of trimming the image takes a lot of time. So in practice, even if Photokit has its own caching strategy, it's still hard to avoid this time-consuming part. Therefore, the above points to optimize the image of the strategy focus on the reduction of image size, asynchronous requests and do several aspects of caching.
The third part of the article--how to encapsulate a common approach based on Photokit and Alassetlibrary, explore the two--photokit details of the IOS development Photo framework (below)
Detailed description of the picture frame of IOS development (--photokit)