如何使用PHCachingImageManager

时间:2015-05-29 15:53:49

标签: ios swift photosframework phasset

我知道这个问题已经存在,但我不认为给定的答案是令人满意/完整的:How can IOS Photos app can show hundreds of photos in one screen?

我想要实现的目标

我想要像whatsapp(iOS)中的图像选择(见截图)。当您打开相机时,还有一个水平滑块,您可以在其中查看图库中的所有图像。

whatsapp screenshot

我尝试了什么

现在我的appDelegate中有以下代码:

#include <wrl\client.h>

using Microsoft::WRL::ComPtr;

void GetApplicationDataDirectory(wchar_t* dir, size_t maxsize)
{
    if (!maxsize) return;
    *dir = 0;
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
    // You can use the Win32 SHGetKnownFolderPath as well which is just
    // a wrapper that does the same thing.

    // On Windows XP, you use the older SHGetFolderPath function with
    // different constants that have the same meaning.

    ComPtr<IKnownFolderManager> mgr;
    HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager,
        nullptr, CLSCTX_INPROC_SERVER, IID_IKnownFolderManager, (LPVOID*) &mgr);
    if (SUCCEEDED(hr))
    {
        ComPtr<IKnownFolder> folder;
        hr = mgr->GetFolder(FOLDERID_LocalAppData, &folder);
        if (SUCCEEDED(hr))
        {
            LPWSTR szPath = 0;
            hr = folder->GetPath(0, &szPath);
            if (SUCCEEDED(hr))
            {
                // A big different with Windows desktop apps is here.
                // With Windows Store apps, your appdata directory is 
                // isolated per-user and per-app. In Windows desktop,
                // it is only isolated per-user so you have to create
                // your own unique subdir and other Windows desktop apps
                // can mess with your data
                wcscpy_s(dir, maxsize, szPath);
                wcscat_s(dir, maxsize, L”\\MyUniqueApplicationName”);
                CreateDirectory(dir, nullptr);
                CoTaskMemFree(szPath);
            }
        }
    }
#else // Windows Store WinRT app
    auto folder = Windows::Storage::ApplicationData::Current
        ->LocalFolder;
    wcscpy_s(dir, maxsize, folder->Path->Data());
#endif
}

稍后我将图像加载到UITableViewController中并在scroll上调用以下函数:

let options = PHFetchOptions()

options.sortDescriptors = [
    NSSortDescriptor(key: "creationDate", ascending: true)
]
if let results = PHAsset.fetchAssetsWithMediaType(.Image, options: options) {

    results.enumerateObjectsUsingBlock { (object, idx, _) in
        if let asset = object as? PHAsset {
            Variables.assets.append(asset)
        }
    }

    println(Variables.assets.count)

    Variables.imageManager.startCachingImagesForAssets(Variables.assets, targetSize: CGSizeMake(viewWidth, viewWidth), contentMode: .AspectFill, options: self.requestOptions)
}

这很有效,但我遇到的问题是,在每个应用程序启动时,我的所有资产都会被缓存。这是解决我问题的正确方法吗?如何像whatsapp一样实时显示图库照片?

1 个答案:

答案 0 :(得分:4)

参考此Photos Framework example 在这个项目中,您应该查看文件AAPLAssetGridViewController.m以及它如何根据您的滚动位置处理缓存。

 - (void)updateCachedAssets
        {
            BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil;
            if (!isViewVisible) { return; }

            // The preheat window is twice the height of the visible rect
            CGRect preheatRect = self.collectionView.bounds;
            preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect));

            // If scrolled by a "reasonable" amount...
            CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));
            if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0f) {

                // Compute the assets to start caching and to stop caching.
                NSMutableArray *addedIndexPaths = [NSMutableArray array];
                NSMutableArray *removedIndexPaths = [NSMutableArray array];

                [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) {
                    NSArray *indexPaths = [self.collectionView aapl_indexPathsForElementsInRect:removedRect];
                    [removedIndexPaths addObjectsFromArray:indexPaths];
                } addedHandler:^(CGRect addedRect) {
                    NSArray *indexPaths = [self.collectionView aapl_indexPathsForElementsInRect:addedRect];
                    [addedIndexPaths addObjectsFromArray:indexPaths];
                }];

                NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];
                NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];

                [self.imageManager startCachingImagesForAssets:assetsToStartCaching
                                                    targetSize:AssetGridThumbnailSize
                                                   contentMode:PHImageContentModeAspectFill
                                                       options:nil];
                [self.imageManager stopCachingImagesForAssets:assetsToStopCaching
                                                   targetSize:AssetGridThumbnailSize
                                                  contentMode:PHImageContentModeAspectFill
                                                      options:nil];

                 self.previousPreheatRect = preheatRect;
            }
        }
        //In your case this computeDifference method changes to handle horizontal scrolling
            - (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler
            {
                if (CGRectIntersectsRect(newRect, oldRect)) {
                    CGFloat oldMaxY = CGRectGetMaxY(oldRect);
                    CGFloat oldMinY = CGRectGetMinY(oldRect);
                    CGFloat newMaxY = CGRectGetMaxY(newRect);
                    CGFloat newMinY = CGRectGetMinY(newRect);
                    if (newMaxY > oldMaxY) {
                        CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));
                        addedHandler(rectToAdd);
                    }
                    if (oldMinY > newMinY) {
                        CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));
                        addedHandler(rectToAdd);
                    }
                    if (newMaxY < oldMaxY) {
                        CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));
                        removedHandler(rectToRemove);
                    }
                    if (oldMinY < newMinY) {
                        CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));
                        removedHandler(rectToRemove);
                    }
                } else {
                    addedHandler(newRect);
                    removedHandler(oldRect);
                }
            }



- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths
    {
        if (indexPaths.count == 0) { return nil; }

        NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];
        for (NSIndexPath *indexPath in indexPaths) {
            PHAsset *asset = self.assetsFetchResults[indexPath.item];
            [assets addObject:asset];
        }
        return assets;
    }

图像缓存管理器使用所需大小的资源进行加热,然后您可以从图像缓存管理器本身检索它们。

希望它对你有所帮助。