diff --git a/.gitignore b/.gitignore index 7e11480..c67c252 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ profile DerivedData # Demo Images -FastImageCacheDemo/Demo Images/*.jpg +FastImageCache/FastImageCacheDemo/Demo Images/*.jpg +Carthage diff --git a/FastImageCache/FICUtilities.h b/FastImageCache/FICUtilities.h deleted file mode 100644 index d6292e6..0000000 --- a/FastImageCache/FICUtilities.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// FICUtilities.h -// FastImageCache -// -// Copyright (c) 2013 Path, Inc. -// See LICENSE for full license agreement. -// - -#import "FICImports.h" - -size_t FICByteAlign(size_t bytesPerRow, size_t alignment); -size_t FICByteAlignForCoreAnimation(size_t bytesPerRow); - -NSString * FICStringWithUUIDBytes(CFUUIDBytes UUIDBytes); -CFUUIDBytes FICUUIDBytesWithString(NSString *string); -CFUUIDBytes FICUUIDBytesFromMD5HashOfString(NSString *MD5Hash); // Useful for computing an entity's UUID from a URL, for example - diff --git a/FastImageCache/FastImageCache.xcodeproj/project.pbxproj b/FastImageCache/FastImageCache.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d889c59 --- /dev/null +++ b/FastImageCache/FastImageCache.xcodeproj/project.pbxproj @@ -0,0 +1,662 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B2E5676E1B316D5800906840 /* FastImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E5676D1B316D5800906840 /* FastImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2E567741B316D5800906840 /* FastImageCache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2E567681B316D5800906840 /* FastImageCache.framework */; }; + B2E5677B1B316D5800906840 /* FastImageCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5677A1B316D5800906840 /* FastImageCacheTests.m */; }; + B2E567941B316D9600906840 /* FICEntity.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E567851B316D9600906840 /* FICEntity.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2E567951B316D9600906840 /* FICImageCache+FICErrorLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E567861B316D9600906840 /* FICImageCache+FICErrorLogging.h */; }; + B2E567961B316D9600906840 /* FICImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E567871B316D9600906840 /* FICImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2E567971B316D9600906840 /* FICImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567881B316D9600906840 /* FICImageCache.m */; }; + B2E567981B316D9600906840 /* FICImageFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E567891B316D9600906840 /* FICImageFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2E567991B316D9600906840 /* FICImageFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5678A1B316D9600906840 /* FICImageFormat.m */; }; + B2E5679A1B316D9600906840 /* FICImageTable.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E5678B1B316D9600906840 /* FICImageTable.h */; }; + B2E5679B1B316D9600906840 /* FICImageTable.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5678C1B316D9600906840 /* FICImageTable.m */; }; + B2E5679C1B316D9600906840 /* FICImageTableChunk.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E5678D1B316D9600906840 /* FICImageTableChunk.h */; }; + B2E5679D1B316D9600906840 /* FICImageTableChunk.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5678E1B316D9600906840 /* FICImageTableChunk.m */; }; + B2E5679E1B316D9600906840 /* FICImageTableEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E5678F1B316D9600906840 /* FICImageTableEntry.h */; }; + B2E5679F1B316D9600906840 /* FICImageTableEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567901B316D9600906840 /* FICImageTableEntry.m */; }; + B2E567A01B316D9600906840 /* FICImports.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E567911B316D9600906840 /* FICImports.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2E567A11B316D9600906840 /* FICUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E567921B316D9600906840 /* FICUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2E567A21B316D9600906840 /* FICUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567931B316D9600906840 /* FICUtilities.m */; }; + B2E567AC1B316DCA00906840 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567AB1B316DCA00906840 /* main.m */; }; + B2E567DA1B316E1000906840 /* FICDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567CF1B316E1000906840 /* FICDAppDelegate.m */; }; + B2E567DB1B316E1000906840 /* FICDFullscreenPhotoDisplayController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567D11B316E1000906840 /* FICDFullscreenPhotoDisplayController.m */; }; + B2E567DC1B316E1000906840 /* FICDPhoto.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567D31B316E1000906840 /* FICDPhoto.m */; }; + B2E567DD1B316E1000906840 /* FICDPhotosTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567D51B316E1000906840 /* FICDPhotosTableViewCell.m */; }; + B2E567DE1B316E1000906840 /* FICDTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567D71B316E1000906840 /* FICDTableView.m */; }; + B2E567DF1B316E1000906840 /* FICDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567D91B316E1000906840 /* FICDViewController.m */; }; + B2E567E41B316E2200906840 /* fetch_demo_images.sh in Resources */ = {isa = PBXBuildFile; fileRef = B2E567E31B316E2200906840 /* fetch_demo_images.sh */; }; + B2E567E61B316E3700906840 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B2E567E51B316E3700906840 /* Assets.xcassets */; }; + B2E567E71B316E5F00906840 /* FICUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567931B316D9600906840 /* FICUtilities.m */; }; + B2E567E81B316E6600906840 /* FICImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567881B316D9600906840 /* FICImageCache.m */; }; + B2E567E91B316E6600906840 /* FICImageFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5678A1B316D9600906840 /* FICImageFormat.m */; }; + B2E567EA1B316E6600906840 /* FICImageTable.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5678C1B316D9600906840 /* FICImageTable.m */; }; + B2E567EB1B316E6600906840 /* FICImageTableChunk.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E5678E1B316D9600906840 /* FICImageTableChunk.m */; }; + B2E567EC1B316E6600906840 /* FICImageTableEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E567901B316D9600906840 /* FICImageTableEntry.m */; }; + BFD6BFFB1B68FD5D005292DC /* Demo Images in Resources */ = {isa = PBXBuildFile; fileRef = BFD6BFFA1B68FD5D005292DC /* Demo Images */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + B2E567751B316D5800906840 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B2E5675F1B316D5800906840 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B2E567671B316D5800906840; + remoteInfo = FastImageCache; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + B2E567681B316D5800906840 /* FastImageCache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FastImageCache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B2E5676C1B316D5800906840 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B2E5676D1B316D5800906840 /* FastImageCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FastImageCache.h; sourceTree = ""; }; + B2E567731B316D5800906840 /* FastImageCacheTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FastImageCacheTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B2E567791B316D5800906840 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B2E5677A1B316D5800906840 /* FastImageCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FastImageCacheTests.m; sourceTree = ""; }; + B2E567851B316D9600906840 /* FICEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICEntity.h; sourceTree = ""; }; + B2E567861B316D9600906840 /* FICImageCache+FICErrorLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FICImageCache+FICErrorLogging.h"; sourceTree = ""; }; + B2E567871B316D9600906840 /* FICImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageCache.h; sourceTree = ""; }; + B2E567881B316D9600906840 /* FICImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageCache.m; sourceTree = ""; }; + B2E567891B316D9600906840 /* FICImageFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageFormat.h; sourceTree = ""; }; + B2E5678A1B316D9600906840 /* FICImageFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageFormat.m; sourceTree = ""; }; + B2E5678B1B316D9600906840 /* FICImageTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageTable.h; sourceTree = ""; }; + B2E5678C1B316D9600906840 /* FICImageTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageTable.m; sourceTree = ""; }; + B2E5678D1B316D9600906840 /* FICImageTableChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageTableChunk.h; sourceTree = ""; }; + B2E5678E1B316D9600906840 /* FICImageTableChunk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageTableChunk.m; sourceTree = ""; }; + B2E5678F1B316D9600906840 /* FICImageTableEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageTableEntry.h; sourceTree = ""; }; + B2E567901B316D9600906840 /* FICImageTableEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageTableEntry.m; sourceTree = ""; }; + B2E567911B316D9600906840 /* FICImports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImports.h; sourceTree = ""; }; + B2E567921B316D9600906840 /* FICUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICUtilities.h; sourceTree = ""; }; + B2E567931B316D9600906840 /* FICUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICUtilities.m; sourceTree = ""; }; + B2E567A71B316DCA00906840 /* FastImageCacheDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FastImageCacheDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B2E567AA1B316DCA00906840 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B2E567AB1B316DCA00906840 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B2E567CE1B316E1000906840 /* FICDAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDAppDelegate.h; sourceTree = ""; }; + B2E567CF1B316E1000906840 /* FICDAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDAppDelegate.m; sourceTree = ""; }; + B2E567D01B316E1000906840 /* FICDFullscreenPhotoDisplayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDFullscreenPhotoDisplayController.h; sourceTree = ""; }; + B2E567D11B316E1000906840 /* FICDFullscreenPhotoDisplayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDFullscreenPhotoDisplayController.m; sourceTree = ""; }; + B2E567D21B316E1000906840 /* FICDPhoto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDPhoto.h; sourceTree = ""; }; + B2E567D31B316E1000906840 /* FICDPhoto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDPhoto.m; sourceTree = ""; }; + B2E567D41B316E1000906840 /* FICDPhotosTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDPhotosTableViewCell.h; sourceTree = ""; }; + B2E567D51B316E1000906840 /* FICDPhotosTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDPhotosTableViewCell.m; sourceTree = ""; }; + B2E567D61B316E1000906840 /* FICDTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDTableView.h; sourceTree = ""; }; + B2E567D71B316E1000906840 /* FICDTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDTableView.m; sourceTree = ""; }; + B2E567D81B316E1000906840 /* FICDViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDViewController.h; sourceTree = ""; }; + B2E567D91B316E1000906840 /* FICDViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDViewController.m; sourceTree = ""; }; + B2E567E31B316E2200906840 /* fetch_demo_images.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = fetch_demo_images.sh; sourceTree = ""; }; + B2E567E51B316E3700906840 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B2E567ED1B316EBF00906840 /* FastImageCacheDemo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FastImageCacheDemo-Prefix.pch"; sourceTree = ""; }; + BFD6BFFA1B68FD5D005292DC /* Demo Images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Demo Images"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B2E567641B316D5800906840 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2E567701B316D5800906840 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B2E567741B316D5800906840 /* FastImageCache.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2E567A41B316DCA00906840 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B2E5675E1B316D5800906840 = { + isa = PBXGroup; + children = ( + B2E5676A1B316D5800906840 /* FastImageCache */, + B2E567771B316D5800906840 /* FastImageCacheTests */, + B2E567A81B316DCA00906840 /* FastImageCacheDemo */, + B2E567691B316D5800906840 /* Products */, + ); + sourceTree = ""; + }; + B2E567691B316D5800906840 /* Products */ = { + isa = PBXGroup; + children = ( + B2E567681B316D5800906840 /* FastImageCache.framework */, + B2E567731B316D5800906840 /* FastImageCacheTests.xctest */, + B2E567A71B316DCA00906840 /* FastImageCacheDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + B2E5676A1B316D5800906840 /* FastImageCache */ = { + isa = PBXGroup; + children = ( + B2E567841B316D9600906840 /* FastImageCache */, + B2E5676D1B316D5800906840 /* FastImageCache.h */, + B2E5676B1B316D5800906840 /* Supporting Files */, + ); + path = FastImageCache; + sourceTree = ""; + }; + B2E5676B1B316D5800906840 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B2E5676C1B316D5800906840 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B2E567771B316D5800906840 /* FastImageCacheTests */ = { + isa = PBXGroup; + children = ( + B2E5677A1B316D5800906840 /* FastImageCacheTests.m */, + B2E567781B316D5800906840 /* Supporting Files */, + ); + path = FastImageCacheTests; + sourceTree = ""; + }; + B2E567781B316D5800906840 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B2E567791B316D5800906840 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B2E567841B316D9600906840 /* FastImageCache */ = { + isa = PBXGroup; + children = ( + B2E567851B316D9600906840 /* FICEntity.h */, + B2E567861B316D9600906840 /* FICImageCache+FICErrorLogging.h */, + B2E567871B316D9600906840 /* FICImageCache.h */, + B2E567881B316D9600906840 /* FICImageCache.m */, + B2E567891B316D9600906840 /* FICImageFormat.h */, + B2E5678A1B316D9600906840 /* FICImageFormat.m */, + B2E5678B1B316D9600906840 /* FICImageTable.h */, + B2E5678C1B316D9600906840 /* FICImageTable.m */, + B2E5678D1B316D9600906840 /* FICImageTableChunk.h */, + B2E5678E1B316D9600906840 /* FICImageTableChunk.m */, + B2E5678F1B316D9600906840 /* FICImageTableEntry.h */, + B2E567901B316D9600906840 /* FICImageTableEntry.m */, + B2E567911B316D9600906840 /* FICImports.h */, + B2E567921B316D9600906840 /* FICUtilities.h */, + B2E567931B316D9600906840 /* FICUtilities.m */, + ); + path = FastImageCache; + sourceTree = ""; + }; + B2E567A81B316DCA00906840 /* FastImageCacheDemo */ = { + isa = PBXGroup; + children = ( + B2E567E31B316E2200906840 /* fetch_demo_images.sh */, + BFD6BFFA1B68FD5D005292DC /* Demo Images */, + B2E567CD1B316E1000906840 /* Classes */, + B2E567A91B316DCA00906840 /* Supporting Files */, + ); + path = FastImageCacheDemo; + sourceTree = ""; + }; + B2E567A91B316DCA00906840 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B2E567ED1B316EBF00906840 /* FastImageCacheDemo-Prefix.pch */, + B2E567E51B316E3700906840 /* Assets.xcassets */, + B2E567AA1B316DCA00906840 /* Info.plist */, + B2E567AB1B316DCA00906840 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B2E567CD1B316E1000906840 /* Classes */ = { + isa = PBXGroup; + children = ( + B2E567CE1B316E1000906840 /* FICDAppDelegate.h */, + B2E567CF1B316E1000906840 /* FICDAppDelegate.m */, + B2E567D01B316E1000906840 /* FICDFullscreenPhotoDisplayController.h */, + B2E567D11B316E1000906840 /* FICDFullscreenPhotoDisplayController.m */, + B2E567D21B316E1000906840 /* FICDPhoto.h */, + B2E567D31B316E1000906840 /* FICDPhoto.m */, + B2E567D41B316E1000906840 /* FICDPhotosTableViewCell.h */, + B2E567D51B316E1000906840 /* FICDPhotosTableViewCell.m */, + B2E567D61B316E1000906840 /* FICDTableView.h */, + B2E567D71B316E1000906840 /* FICDTableView.m */, + B2E567D81B316E1000906840 /* FICDViewController.h */, + B2E567D91B316E1000906840 /* FICDViewController.m */, + ); + path = Classes; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B2E567651B316D5800906840 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + B2E5679A1B316D9600906840 /* FICImageTable.h in Headers */, + B2E5679E1B316D9600906840 /* FICImageTableEntry.h in Headers */, + B2E567941B316D9600906840 /* FICEntity.h in Headers */, + B2E567A01B316D9600906840 /* FICImports.h in Headers */, + B2E567981B316D9600906840 /* FICImageFormat.h in Headers */, + B2E567A11B316D9600906840 /* FICUtilities.h in Headers */, + B2E5679C1B316D9600906840 /* FICImageTableChunk.h in Headers */, + B2E567951B316D9600906840 /* FICImageCache+FICErrorLogging.h in Headers */, + B2E567961B316D9600906840 /* FICImageCache.h in Headers */, + B2E5676E1B316D5800906840 /* FastImageCache.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B2E567671B316D5800906840 /* FastImageCache */ = { + isa = PBXNativeTarget; + buildConfigurationList = B2E5677E1B316D5800906840 /* Build configuration list for PBXNativeTarget "FastImageCache" */; + buildPhases = ( + B2E567631B316D5800906840 /* Sources */, + B2E567641B316D5800906840 /* Frameworks */, + B2E567651B316D5800906840 /* Headers */, + B2E567661B316D5800906840 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FastImageCache; + productName = FastImageCache; + productReference = B2E567681B316D5800906840 /* FastImageCache.framework */; + productType = "com.apple.product-type.framework"; + }; + B2E567721B316D5800906840 /* FastImageCacheTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B2E567811B316D5800906840 /* Build configuration list for PBXNativeTarget "FastImageCacheTests" */; + buildPhases = ( + B2E5676F1B316D5800906840 /* Sources */, + B2E567701B316D5800906840 /* Frameworks */, + B2E567711B316D5800906840 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + B2E567761B316D5800906840 /* PBXTargetDependency */, + ); + name = FastImageCacheTests; + productName = FastImageCacheTests; + productReference = B2E567731B316D5800906840 /* FastImageCacheTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + B2E567A61B316DCA00906840 /* FastImageCacheDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = B2E567C71B316DCB00906840 /* Build configuration list for PBXNativeTarget "FastImageCacheDemo" */; + buildPhases = ( + B2E567A31B316DCA00906840 /* Sources */, + B2E567A41B316DCA00906840 /* Frameworks */, + B2E567A51B316DCA00906840 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FastImageCacheDemo; + productName = FastImageCacheDemo; + productReference = B2E567A71B316DCA00906840 /* FastImageCacheDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B2E5675F1B316D5800906840 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = Path; + TargetAttributes = { + B2E567671B316D5800906840 = { + CreatedOnToolsVersion = 6.3.2; + }; + B2E567721B316D5800906840 = { + CreatedOnToolsVersion = 6.3.2; + }; + B2E567A61B316DCA00906840 = { + CreatedOnToolsVersion = 6.3.2; + }; + }; + }; + buildConfigurationList = B2E567621B316D5800906840 /* Build configuration list for PBXProject "FastImageCache" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B2E5675E1B316D5800906840; + productRefGroup = B2E567691B316D5800906840 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B2E567671B316D5800906840 /* FastImageCache */, + B2E567721B316D5800906840 /* FastImageCacheTests */, + B2E567A61B316DCA00906840 /* FastImageCacheDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B2E567661B316D5800906840 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2E567711B316D5800906840 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2E567A51B316DCA00906840 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B2E567E41B316E2200906840 /* fetch_demo_images.sh in Resources */, + BFD6BFFB1B68FD5D005292DC /* Demo Images in Resources */, + B2E567E61B316E3700906840 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B2E567631B316D5800906840 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B2E5679B1B316D9600906840 /* FICImageTable.m in Sources */, + B2E5679D1B316D9600906840 /* FICImageTableChunk.m in Sources */, + B2E567971B316D9600906840 /* FICImageCache.m in Sources */, + B2E567A21B316D9600906840 /* FICUtilities.m in Sources */, + B2E5679F1B316D9600906840 /* FICImageTableEntry.m in Sources */, + B2E567991B316D9600906840 /* FICImageFormat.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2E5676F1B316D5800906840 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B2E5677B1B316D5800906840 /* FastImageCacheTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2E567A31B316DCA00906840 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B2E567DA1B316E1000906840 /* FICDAppDelegate.m in Sources */, + B2E567EB1B316E6600906840 /* FICImageTableChunk.m in Sources */, + B2E567E91B316E6600906840 /* FICImageFormat.m in Sources */, + B2E567AC1B316DCA00906840 /* main.m in Sources */, + B2E567EA1B316E6600906840 /* FICImageTable.m in Sources */, + B2E567DD1B316E1000906840 /* FICDPhotosTableViewCell.m in Sources */, + B2E567E81B316E6600906840 /* FICImageCache.m in Sources */, + B2E567EC1B316E6600906840 /* FICImageTableEntry.m in Sources */, + B2E567DF1B316E1000906840 /* FICDViewController.m in Sources */, + B2E567DC1B316E1000906840 /* FICDPhoto.m in Sources */, + B2E567DB1B316E1000906840 /* FICDFullscreenPhotoDisplayController.m in Sources */, + B2E567DE1B316E1000906840 /* FICDTableView.m in Sources */, + B2E567E71B316E5F00906840 /* FICUtilities.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + B2E567761B316D5800906840 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B2E567671B316D5800906840 /* FastImageCache */; + targetProxy = B2E567751B316D5800906840 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + B2E5677C1B316D5800906840 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + B2E5677D1B316D5800906840 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + B2E5677F1B316D5800906840 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = FastImageCache/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.path.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + B2E567801B316D5800906840 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = FastImageCache/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.path.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + B2E567821B316D5800906840 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = FastImageCacheTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.path.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B2E567831B316D5800906840 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = FastImageCacheTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.path.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + B2E567C81B316DCB00906840 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = Icon; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = FastImageCacheDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.path.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B2E567C91B316DCB00906840 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = Icon; + INFOPLIST_FILE = FastImageCacheDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.path.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B2E567621B316D5800906840 /* Build configuration list for PBXProject "FastImageCache" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B2E5677C1B316D5800906840 /* Debug */, + B2E5677D1B316D5800906840 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B2E5677E1B316D5800906840 /* Build configuration list for PBXNativeTarget "FastImageCache" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B2E5677F1B316D5800906840 /* Debug */, + B2E567801B316D5800906840 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B2E567811B316D5800906840 /* Build configuration list for PBXNativeTarget "FastImageCacheTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B2E567821B316D5800906840 /* Debug */, + B2E567831B316D5800906840 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B2E567C71B316DCB00906840 /* Build configuration list for PBXNativeTarget "FastImageCacheDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B2E567C81B316DCB00906840 /* Debug */, + B2E567C91B316DCB00906840 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B2E5675F1B316D5800906840 /* Project object */; +} diff --git a/FastImageCache/FastImageCache.xcodeproj/xcshareddata/xcschemes/FastImageCache.xcscheme b/FastImageCache/FastImageCache.xcodeproj/xcshareddata/xcschemes/FastImageCache.xcscheme new file mode 100644 index 0000000..e561d4a --- /dev/null +++ b/FastImageCache/FastImageCache.xcodeproj/xcshareddata/xcschemes/FastImageCache.xcscheme @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FastImageCache/FastImageCache/FastImageCache.h b/FastImageCache/FastImageCache/FastImageCache.h new file mode 100644 index 0000000..a78ddc1 --- /dev/null +++ b/FastImageCache/FastImageCache/FastImageCache.h @@ -0,0 +1,19 @@ +// +// FastImageCache.h +// FastImageCache +// +// Created by Rui Peres on 17/06/2015. +// Copyright (c) 2015 Path. All rights reserved. +// + +#import + +//! Project version number for FastImageCache. +FOUNDATION_EXPORT double FastImageCacheVersionNumber; + +//! Project version string for FastImageCache. +FOUNDATION_EXPORT const unsigned char FastImageCacheVersionString[]; + +#import +#import +#import \ No newline at end of file diff --git a/FastImageCache/FICEntity.h b/FastImageCache/FastImageCache/FastImageCache/FICEntity.h similarity index 85% rename from FastImageCache/FICEntity.h rename to FastImageCache/FastImageCache/FastImageCache/FICEntity.h index fec135d..5a4eccd 100644 --- a/FastImageCache/FICEntity.h +++ b/FastImageCache/FastImageCache/FastImageCache/FICEntity.h @@ -7,6 +7,9 @@ // #import "FICImports.h" +@class FICImageFormat; + +NS_ASSUME_NONNULL_BEGIN typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextSize); @@ -23,7 +26,7 @@ typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextS @discussion Within each image table, each entry is identified by an entity's UUID. Ideally, this value should never change for an entity. For example, if your entity class is a person model, its UUID might be an API-assigned, unchanging, unique user ID. No matter how the properties of the person change, its user ID should never change. */ -@property (nonatomic, copy, readonly) NSString *UUID; +@property (nonatomic, copy, readonly) NSString *fic_UUID; /** A string that uniquely identifies an entity's source image. @@ -31,7 +34,7 @@ typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextS @discussion While `` should be unchanging, a source image UUID might change. For example, if your entity class is a person model, its source image UUID might change every time the person changes their profile photo. In this case, the source image UUID might be a hash of the profile photo URL (assuming each image is given a unique URL). */ -@property (nonatomic, copy, readonly) NSString *sourceImageUUID; +@property (nonatomic, copy, readonly) NSString *fic_sourceImageUUID; /** Returns the source image URL associated with a specific format name. @@ -51,7 +54,8 @@ typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextS @see FICImageFormat @see [FICImageCacheDelegate imageCache:wantsSourceImageForEntity:withFormatName:completionBlock:] */ -- (NSURL *)sourceImageURLWithFormatName:(NSString *)formatName; +- (nullable NSURL *)fic_sourceImageURLWithFormatName:(NSString *)formatName; + /** Returns the drawing block for a specific image and format name. @@ -72,6 +76,16 @@ typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextS @note This block will always be called from the serial dispatch queue used by the image cache. */ -- (FICEntityImageDrawingBlock)drawingBlockForImage:(UIImage *)image withFormatName:(NSString *)formatName; +- (nullable FICEntityImageDrawingBlock)fic_drawingBlockForImage:(UIImage *)image withFormatName:(NSString *)formatName; + +@optional +/** + Returns the image for a format + + @param format The image format that identifies which image table is requesting the source image. + */ +- (nullable UIImage *)fic_imageForFormat:(FICImageFormat *)format; @end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/FastImageCache/FICImageCache+FICErrorLogging.h b/FastImageCache/FastImageCache/FastImageCache/FICImageCache+FICErrorLogging.h similarity index 100% rename from FastImageCache/FICImageCache+FICErrorLogging.h rename to FastImageCache/FastImageCache/FastImageCache/FICImageCache+FICErrorLogging.h diff --git a/FastImageCache/FICImageCache.h b/FastImageCache/FastImageCache/FastImageCache/FICImageCache.h similarity index 84% rename from FastImageCache/FICImageCache.h rename to FastImageCache/FastImageCache/FastImageCache/FICImageCache.h index b6f850a..bb102a0 100644 --- a/FastImageCache/FICImageCache.h +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageCache.h @@ -13,8 +13,10 @@ @protocol FICEntity; @protocol FICImageCacheDelegate; -typedef void (^FICImageCacheCompletionBlock)(id entity, NSString *formatName, UIImage *image); -typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); +typedef void (^FICImageCacheCompletionBlock)(id _Nullable entity, NSString * _Nonnull formatName, UIImage * _Nullable image); +typedef void (^FICImageRequestCompletionBlock)(UIImage * _Nullable sourceImage); + +NS_ASSUME_NONNULL_BEGIN /** `FICImageCache` is the primary class for managing and interacting with the image cache. Applications using the image cache create one or more `` @@ -24,6 +26,14 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); */ @interface FICImageCache : NSObject +/** + The namespace of the image cache. + + @discussion Namespace is responsible for isolation of dirrerent image cache instances on file system level. Namespace should be unique across application. + */ + +@property (readonly, nonatomic) NSString *nameSpace; + ///---------------------------- /// @name Managing the Delegate ///---------------------------- @@ -36,15 +46,47 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); */ @property (nonatomic, weak) id delegate; +///--------------------------------------- +/// @name Creating Image Cache instances +///--------------------------------------- + +/** + Returns new image cache. + + @return A new instance of `FICImageCache`. + + @param nameSpace The namespace that uniquely identifies current image cahce entity. If no nameSpace given, default namespace will be used. + + @note Fast Image Cache can either be used as a singleton for convenience or can exist as multiple instances. + However, all instances of `FICImageCache` will make use same dispatch queue. To separate location on disk for storing image tables namespaces are used. + + @see [FICImageCache dispatchQueue] + */ + +- (instancetype)initWithNameSpace:(NSString *)nameSpace; + ///--------------------------------------- /// @name Accessing the Shared Image Cache ///--------------------------------------- /** - Convenience accessor to retrieve a shared image cache instance. + Returns the shared image cache. + + @return A shared instance of `FICImageCache`. + + @note Shared instance always binded to default namespace. + + @see [FICImageCache dispatchQueue] */ + (instancetype)sharedImageCache; +/** + Returns the shared dispatch queue used by all instances of `FICImageCache`. + + @return A generic, shared dispatch queue of type `dispatch_queue_t`. + + @note All instances of `FICImageCache` make use a single, shared dispatch queue to do their work. + */ + (dispatch_queue_t)dispatchQueue; ///--------------------------------- @@ -58,7 +100,7 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); @note Once the image formats have been set, subsequent calls to this method will do nothing. */ -- (void)setFormats:(NSArray *)formats; +- (void)setFormats:(NSArray *)formats; /** Returns an image format previously associated with the image cache. @@ -67,7 +109,7 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); @return An image format with the name `formatName` or `nil` if no format with that name exists. */ -- (FICImageFormat *)formatWithName:(NSString *)formatName; +- (nullable FICImageFormat *)formatWithName:(NSString *)formatName; /** Returns all the image formats of the same family previously associated with the image cache. @@ -76,7 +118,7 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); @return An array of `` objects whose family is `family` or `nil` if no format belongs to that family. */ -- (NSArray *)formatsWithFamily:(NSString *)family; +- (nullable NSArray *)formatsWithFamily:(NSString *)family; ///----------------------------------------------- /// @name Storing, Retrieving, and Deleting Images @@ -101,14 +143,14 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); typedef void (^FICImageCacheCompletionBlock)(id entity, NSString *formatName, UIImage *image) */ -- (void)setImage:(UIImage *)image forEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(FICImageCacheCompletionBlock)completionBlock; +- (void)setImage:(UIImage *)image forEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(nullable FICImageCacheCompletionBlock)completionBlock; /** Attempts to synchronously retrieve an image from the image cache. @param entity The entity that uniquely identifies the source image. - @param formatName The format name that uniquely identifies which image table to look in for the cached image. + @param formatName The format name that uniquely identifies which image table to look in for the cached image. Must not be nil. @param completionBlock The completion block that is called when the requested image is available or if an error occurs. @@ -128,14 +170,14 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); @note You can always rely on the completion block being called. If an error occurs for any reason, the `image` parameter of the completion block will be `nil`. See <[FICImageCacheDelegate imageCache:errorDidOccurWithMessage:]> for information about being notified when errors occur. */ -- (BOOL)retrieveImageForEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(FICImageCacheCompletionBlock)completionBlock; +- (BOOL)retrieveImageForEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(nullable FICImageCacheCompletionBlock)completionBlock; /** Asynchronously retrieves an image from the image cache. @param entity The entity that uniquely identifies the source image. - @param formatName The format name that uniquely identifies which image table to look in for the cached image. + @param formatName The format name that uniquely identifies which image table to look in for the cached image. Must not be nil. @param completionBlock The completion block that is called when the requested image is available or if an error occurs. @@ -153,7 +195,7 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); @see [FICImageCache retrieveImageForEntity:withFormatName:completionBlock:] */ -- (BOOL)asynchronouslyRetrieveImageForEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(FICImageCacheCompletionBlock)completionBlock; +- (BOOL)asynchronouslyRetrieveImageForEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(nullable FICImageCacheCompletionBlock)completionBlock; /** Deletes an image from the image cache. @@ -213,7 +255,7 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); */ @protocol FICImageCacheDelegate -@required +@optional /** This method is called on the delegate when the image cache needs a source image. @@ -241,9 +283,7 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); the URL returned by <[FICEntity sourceImageURLWithFormatName:]>, deserializing the image data when the request completes, and finally calling this method's completion block to provide the image cache with the source image. */ -- (void)imageCache:(FICImageCache *)imageCache wantsSourceImageForEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(FICImageRequestCompletionBlock)completionBlock; - -@optional +- (void)imageCache:(FICImageCache *)imageCache wantsSourceImageForEntity:(id )entity withFormatName:(NSString *)formatName completionBlock:(nullable FICImageRequestCompletionBlock)completionBlock; /** This method is called on the delegate when the image cache has received an image retrieval cancellation request. @@ -294,3 +334,5 @@ typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage); - (void)imageCache:(FICImageCache *)imageCache errorDidOccurWithMessage:(NSString *)errorMessage; @end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/FastImageCache/FICImageCache.m b/FastImageCache/FastImageCache/FastImageCache/FICImageCache.m similarity index 64% rename from FastImageCache/FICImageCache.m rename to FastImageCache/FastImageCache/FastImageCache/FICImageCache.m index 2d8ae98..1aee1cf 100644 --- a/FastImageCache/FICImageCache.m +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageCache.m @@ -25,8 +25,8 @@ @interface FICImageCache () { NSMutableDictionary *_formats; NSMutableDictionary *_imageTables; NSMutableDictionary *_requests; - __weak id _delegate; + BOOL _delegateImplementsWantsSourceImageForEntityWithFormatNameCompletionBlock; BOOL _delegateImplementsShouldProcessAllFormatsInFamilyForEntity; BOOL _delegateImplementsErrorDidOccurWithMessage; BOOL _delegateImplementsCancelImageLoadingForEntityWithFormatName; @@ -46,24 +46,22 @@ - (void)setDelegate:(id)delegate { if (delegate != _delegate) { _delegate = delegate; + _delegateImplementsWantsSourceImageForEntityWithFormatNameCompletionBlock = [_delegate respondsToSelector:@selector(imageCache:wantsSourceImageForEntity:withFormatName:completionBlock:)]; _delegateImplementsShouldProcessAllFormatsInFamilyForEntity = [_delegate respondsToSelector:@selector(imageCache:shouldProcessAllFormatsInFamily:forEntity:)]; _delegateImplementsErrorDidOccurWithMessage = [_delegate respondsToSelector:@selector(imageCache:errorDidOccurWithMessage:)]; _delegateImplementsCancelImageLoadingForEntityWithFormatName = [_delegate respondsToSelector:@selector(imageCache:cancelImageLoadingForEntity:withFormatName:)]; } } -static FICImageCache *__imageCache = nil; - #pragma mark - Object Lifecycle + (instancetype)sharedImageCache { - if (__imageCache == nil) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - __imageCache = [[[self class] alloc] init]; - }); - } - + static dispatch_once_t onceToken; + static FICImageCache *__imageCache = nil; + dispatch_once(&onceToken, ^{ + __imageCache = [[[self class] alloc] init]; + }); + return __imageCache; } @@ -76,13 +74,17 @@ + (dispatch_queue_t)dispatchQueue { return __imageCacheDispatchQueue; } -- (id)init { +- (instancetype)init { + return [self initWithNameSpace:@"FICDefaultNamespace"]; +} + +- (instancetype)initWithNameSpace:(NSString *)nameSpace { self = [super init]; - - if (self != nil) { + if (self) { _formats = [[NSMutableDictionary alloc] init]; _imageTables = [[NSMutableDictionary alloc] init]; _requests = [[NSMutableDictionary alloc] init]; + _nameSpace = nameSpace; } return self; } @@ -112,6 +114,9 @@ - (void)setFormats:(NSArray *)formats { // Remove any extraneous files in the image tables directory NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *directoryPath = [FICImageTable directoryPath]; + if (self.nameSpace) { + directoryPath = [directoryPath stringByAppendingPathComponent:self.nameSpace]; + } NSArray *fileNames = [fileManager contentsOfDirectoryAtPath:directoryPath error:nil]; for (NSString *fileName in fileNames) { if ([imageTableFiles containsObject:fileName] == NO) { @@ -153,11 +158,13 @@ - (BOOL)asynchronouslyRetrieveImageForEntity:(id )entity withFormatNa } - (BOOL)_retrieveImageForEntity:(id )entity withFormatName:(NSString *)formatName loadSynchronously:(BOOL)loadSynchronously completionBlock:(FICImageCacheCompletionBlock)completionBlock { + NSParameterAssert(formatName); + BOOL imageExists = NO; FICImageTable *imageTable = [_imageTables objectForKey:formatName]; - NSString *entityUUID = [entity UUID]; - NSString *sourceImageUUID = [entity sourceImageUUID]; + NSString *entityUUID = [entity fic_UUID]; + NSString *sourceImageUUID = [entity fic_sourceImageUUID]; if (loadSynchronously == NO && [imageTable entryExistsForEntityUUID:entityUUID sourceImageUUID:sourceImageUUID]) { imageExists = YES; @@ -187,25 +194,41 @@ - (BOOL)_retrieveImageForEntity:(id )entity withFormatName:(NSString } }; - if (image == nil && _delegate != nil) { + if (image == nil) { // No image for this UUID exists in the image table. We'll need to ask the delegate to retrieve the source asset. - NSURL *sourceImageURL = [entity sourceImageURLWithFormatName:formatName]; + NSURL *sourceImageURL = [entity fic_sourceImageURLWithFormatName:formatName]; if (sourceImageURL != nil) { // We check to see if this image is already being fetched. - NSMutableDictionary *requestDictionary = [_requests objectForKey:sourceImageURL]; - if (requestDictionary == nil) { - // If we're here, then we aren't currently fetching this image. - NSMutableDictionary *requestDictionary = [NSMutableDictionary dictionary]; - [_requests setObject:requestDictionary forKey:sourceImageURL]; + BOOL needsToFetch = NO; + @synchronized (_requests) { + NSMutableDictionary *requestDictionary = [_requests objectForKey:sourceImageURL]; + if (requestDictionary == nil) { + // If we're here, then we aren't currently fetching this image. + requestDictionary = [NSMutableDictionary dictionary]; + [_requests setObject:requestDictionary forKey:sourceImageURL]; + needsToFetch = YES; + } _FICAddCompletionBlockForEntity(formatName, requestDictionary, entity, completionBlock); - [_delegate imageCache:self wantsSourceImageForEntity:entity withFormatName:formatName completionBlock:^(UIImage *sourceImage) { - [self _imageDidLoad:sourceImage forURL:sourceImageURL]; - }]; - } else { - // We have an existing request dictionary, which means this URL is currently being fetched. - _FICAddCompletionBlockForEntity(formatName, requestDictionary, entity, completionBlock); + } + + if (needsToFetch) { + @autoreleasepool { + UIImage *image; + if ([entity respondsToSelector:@selector(fic_imageForFormat:)]){ + FICImageFormat *format = [self formatWithName:formatName]; + image = [entity fic_imageForFormat:format]; + } + + if (image){ + [self _imageDidLoad:image forURL:sourceImageURL]; + } else if (_delegateImplementsWantsSourceImageForEntityWithFormatNameCompletionBlock){ + [_delegate imageCache:self wantsSourceImageForEntity:entity withFormatName:formatName completionBlock:^(UIImage *sourceImage) { + [self _imageDidLoad:sourceImage forURL:sourceImageURL]; + }]; + } + } } } else { NSString *message = [NSString stringWithFormat:@"*** FIC Error: %s entity %@ returned a nil source image URL for image format %@.", __PRETTY_FUNCTION__, entity, formatName]; @@ -222,14 +245,20 @@ - (BOOL)_retrieveImageForEntity:(id )entity withFormatName:(NSString } - (void)_imageDidLoad:(UIImage *)image forURL:(NSURL *)URL { - NSDictionary *requestDictionary = [_requests objectForKey:URL]; + NSDictionary *requestDictionary; + @synchronized (_requests) { + requestDictionary = [_requests objectForKey:URL]; + [_requests removeObjectForKey:URL]; + // Now safe to use requestsDictionary outside the lock, because we've taken ownership from _requests + } + if (requestDictionary != nil) { for (NSMutableDictionary *entityDictionary in [requestDictionary allValues]) { id entity = [entityDictionary objectForKey:FICImageCacheEntityKey]; NSString *formatName = [entityDictionary objectForKey:FICImageCacheFormatKey]; NSDictionary *completionBlocksDictionary = [entityDictionary objectForKey:FICImageCacheCompletionBlocksKey]; if (image != nil){ - [self _processImage:image forEntity:entity withFormatName:formatName completionBlocksDictionary:completionBlocksDictionary]; + [self _processImage:image forEntity:entity completionBlocksDictionary:completionBlocksDictionary]; } else { NSArray *completionBlocks = [completionBlocksDictionary objectForKey:formatName]; if (completionBlocks != nil) { @@ -242,12 +271,10 @@ - (void)_imageDidLoad:(UIImage *)image forURL:(NSURL *)URL { } } } - - [_requests removeObjectForKey:URL]; } static void _FICAddCompletionBlockForEntity(NSString *formatName, NSMutableDictionary *entityRequestsDictionary, id entity, FICImageCacheCompletionBlock completionBlock) { - NSString *entityUUID = [entity UUID]; + NSString *entityUUID = [entity fic_UUID]; NSMutableDictionary *requestDictionary = [entityRequestsDictionary objectForKey:entityUUID]; NSMutableDictionary *completionBlocks = nil; @@ -288,63 +315,44 @@ - (void)setImage:(UIImage *)image forEntity:(id )entity withFormatNam completionBlocksDictionary = [NSDictionary dictionaryWithObject:[NSArray arrayWithObject:[completionBlock copy]] forKey:formatName]; } - NSString *entityUUID = [entity UUID]; + NSString *entityUUID = [entity fic_UUID]; FICImageTable *imageTable = [_imageTables objectForKey:formatName]; - [imageTable deleteEntryForEntityUUID:entityUUID]; + if (imageTable) { + [imageTable deleteEntryForEntityUUID:entityUUID]; - [self _processImage:image forEntity:entity withFormatName:formatName completionBlocksDictionary:completionBlocksDictionary]; + [self _processImage:image forEntity:entity completionBlocksDictionary:completionBlocksDictionary]; + } else { + [self _logMessage:[NSString stringWithFormat:@"*** FIC Error: %s Couldn't find image table with format name %@", __PRETTY_FUNCTION__, formatName]]; + } } } -- (void)_processImage:(UIImage *)image forEntity:(id )entity withFormatName:(NSString *)formatName completionBlocksDictionary:(NSDictionary *)completionBlocksDictionary { - FICImageFormat *imageFormat = [_formats objectForKey:formatName]; - NSString *formatFamily = [imageFormat family]; - NSString *entityUUID = [entity UUID]; - NSString *sourceImageUUID = [entity sourceImageUUID]; - - if (formatFamily != nil) { - BOOL shouldProcessAllFormatsInFamily = YES; - if (_delegateImplementsShouldProcessAllFormatsInFamilyForEntity) { - shouldProcessAllFormatsInFamily = [_delegate imageCache:self shouldProcessAllFormatsInFamily:formatFamily forEntity:entity]; - } - // All of the formats in a given family use the same source asset, so once we have that source asset, we can generate all of the family's formats. - for (FICImageTable *table in [_imageTables allValues]) { - FICImageFormat *imageFormat = [table imageFormat]; - NSString *tableFormatFamily = [imageFormat family]; - if ([formatFamily isEqualToString:tableFormatFamily]) { - NSArray *completionBlocks = [completionBlocksDictionary objectForKey:[imageFormat name]]; - - BOOL imageExistsForEntity = [table entryExistsForEntityUUID:entityUUID sourceImageUUID:sourceImageUUID]; - BOOL shouldProcessFamilyFormat = shouldProcessAllFormatsInFamily && imageExistsForEntity == NO; - if (shouldProcessFamilyFormat || [completionBlocks count] > 0) { - [self _processImage:image forEntity:entity imageTable:table completionBlocks:completionBlocks]; - } - } - } - } else { - FICImageTable *imageTable = [_imageTables objectForKey:formatName]; - NSArray *completionBlocks = [completionBlocksDictionary objectForKey:formatName]; +- (void)_processImage:(UIImage *)image forEntity:(id )entity completionBlocksDictionary:(NSDictionary *)completionBlocksDictionary { + for (NSString *formatToProcess in [self formatsToProcessForCompletionBlocks:completionBlocksDictionary + entity:entity]) { + FICImageTable *imageTable = [_imageTables objectForKey:formatToProcess]; + NSArray *completionBlocks = [completionBlocksDictionary objectForKey:formatToProcess]; [self _processImage:image forEntity:entity imageTable:imageTable completionBlocks:completionBlocks]; } } - (void)_processImage:(UIImage *)image forEntity:(id )entity imageTable:(FICImageTable *)imageTable completionBlocks:(NSArray *)completionBlocks { if (imageTable != nil) { - if ([entity UUID] == nil) { + if ([entity fic_UUID] == nil) { [self _logMessage:[NSString stringWithFormat:@"*** FIC Error: %s entity %@ is missing its UUID.", __PRETTY_FUNCTION__, entity]]; return; } - if ([entity sourceImageUUID] == nil) { + if ([entity fic_sourceImageUUID] == nil) { [self _logMessage:[NSString stringWithFormat:@"*** FIC Error: %s entity %@ is missing its source image UUID.", __PRETTY_FUNCTION__, entity]]; return; } - NSString *entityUUID = [entity UUID]; - NSString *sourceImageUUID = [entity sourceImageUUID]; + NSString *entityUUID = [entity fic_UUID]; + NSString *sourceImageUUID = [entity fic_sourceImageUUID]; FICImageFormat *imageFormat = [imageTable imageFormat]; NSString *imageFormatName = [imageFormat name]; - FICEntityImageDrawingBlock imageDrawingBlock = [entity drawingBlockForImage:image withFormatName:imageFormatName]; + FICEntityImageDrawingBlock imageDrawingBlock = [entity fic_drawingBlockForImage:image withFormatName:imageFormatName]; dispatch_async([FICImageCache dispatchQueue], ^{ [imageTable setEntryForEntityUUID:entityUUID sourceImageUUID:sourceImageUUID imageDrawingBlock:imageDrawingBlock]; @@ -363,12 +371,64 @@ - (void)_processImage:(UIImage *)image forEntity:(id )entity imageTab } } +- (NSSet *)formatsToProcessForCompletionBlocks:(NSDictionary *)completionBlocksDictionary entity:(id )entity { + // At the very least, we must process all formats with pending completion blocks + NSMutableSet *formatsToProcess = [NSMutableSet setWithArray:completionBlocksDictionary.allKeys]; + + // Get the list of format families included by the formats we have to process + NSMutableSet *families; + for (NSString *formatToProcess in formatsToProcess) { + FICImageTable *imageTable = _imageTables[formatToProcess]; + FICImageFormat *imageFormat = imageTable.imageFormat; + NSString *tableFormatFamily = imageFormat.family; + if (tableFormatFamily) { + if (!families) { + families = [NSMutableSet set]; + } + [families addObject:tableFormatFamily]; + } + } + + // The delegate can override the list of families to process + if (_delegateImplementsShouldProcessAllFormatsInFamilyForEntity) { + [families minusSet:[families objectsPassingTest:^BOOL(NSString *familyName, BOOL *stop) { + return ![_delegate imageCache:self shouldProcessAllFormatsInFamily:familyName forEntity:entity]; + }]]; + } + + // Ensure that all formats from all of those families are included in the list + if (families.count) { + for (FICImageTable *table in _imageTables.allValues) { + FICImageFormat *imageFormat = table.imageFormat; + NSString *imageFormatName = imageFormat.name; + // If we're already processing this format, keep looking + if ([formatsToProcess containsObject:imageFormatName]) { + continue; + } + + // If this format isn't included in any referenced family, keep looking + if (![families containsObject:imageFormat.family]) { + continue; + } + + // If the image already exists, keep going + if ([table entryExistsForEntityUUID:entity.fic_UUID sourceImageUUID:entity.fic_sourceImageUUID]) { + continue; + } + + [formatsToProcess addObject:imageFormatName]; + } + } + + return formatsToProcess; +} + #pragma mark - Checking for Image Existence - (BOOL)imageExistsForEntity:(id )entity withFormatName:(NSString *)formatName { FICImageTable *imageTable = [_imageTables objectForKey:formatName]; - NSString *entityUUID = [entity UUID]; - NSString *sourceImageUUID = [entity sourceImageUUID]; + NSString *entityUUID = [entity fic_UUID]; + NSString *sourceImageUUID = [entity fic_sourceImageUUID]; BOOL imageExists = [imageTable entryExistsForEntityUUID:entityUUID sourceImageUUID:sourceImageUUID]; @@ -379,38 +439,45 @@ - (BOOL)imageExistsForEntity:(id )entity withFormatName:(NSString *)f - (void)deleteImageForEntity:(id )entity withFormatName:(NSString *)formatName { FICImageTable *imageTable = [_imageTables objectForKey:formatName]; - NSString *entityUUID = [entity UUID]; + NSString *entityUUID = [entity fic_UUID]; [imageTable deleteEntryForEntityUUID:entityUUID]; } - (void)cancelImageRetrievalForEntity:(id )entity withFormatName:(NSString *)formatName { - NSURL *sourceImageURL = [entity sourceImageURLWithFormatName:formatName]; - NSMutableDictionary *requestDictionary = [_requests objectForKey:sourceImageURL]; - if (requestDictionary) { - NSString *entityUUID = [entity UUID]; - NSMutableDictionary *entityRequestsDictionary = [requestDictionary objectForKey:entityUUID]; - if (entityRequestsDictionary) { - NSMutableDictionary *completionBlocksDictionary = [entityRequestsDictionary objectForKey:FICImageCacheCompletionBlocksKey]; - [completionBlocksDictionary removeObjectForKey:formatName]; - - if ([completionBlocksDictionary count] == 0) { - [requestDictionary removeObjectForKey:entityUUID]; - } - - if ([requestDictionary count] == 0) { - [_requests removeObjectForKey:sourceImageURL]; - - if (_delegateImplementsCancelImageLoadingForEntityWithFormatName) { - [_delegate imageCache:self cancelImageLoadingForEntity:entity withFormatName:formatName]; + NSURL *sourceImageURL = [entity fic_sourceImageURLWithFormatName:formatName]; + NSString *entityUUID = [entity fic_UUID]; + + BOOL cancelImageLoadingForEntity = NO; + @synchronized (_requests) { + NSMutableDictionary *requestDictionary = [_requests objectForKey:sourceImageURL]; + if (requestDictionary) { + NSMutableDictionary *entityRequestsDictionary = [requestDictionary objectForKey:entityUUID]; + if (entityRequestsDictionary) { + NSMutableDictionary *completionBlocksDictionary = [entityRequestsDictionary objectForKey:FICImageCacheCompletionBlocksKey]; + [completionBlocksDictionary removeObjectForKey:formatName]; + + if ([completionBlocksDictionary count] == 0) { + [requestDictionary removeObjectForKey:entityUUID]; + } + + if ([requestDictionary count] == 0) { + [_requests removeObjectForKey:sourceImageURL]; + cancelImageLoadingForEntity = YES; } } } } + + if (cancelImageLoadingForEntity && _delegateImplementsCancelImageLoadingForEntityWithFormatName) { + [_delegate imageCache:self cancelImageLoadingForEntity:entity withFormatName:formatName]; + } } - (void)reset { for (FICImageTable *imageTable in [_imageTables allValues]) { - [imageTable reset]; + dispatch_async([[self class] dispatchQueue], ^{ + [imageTable reset]; + }); } } diff --git a/FastImageCache/FICImageFormat.h b/FastImageCache/FastImageCache/FastImageCache/FICImageFormat.h similarity index 72% rename from FastImageCache/FICImageFormat.h rename to FastImageCache/FastImageCache/FastImageCache/FICImageFormat.h index fb5c804..31304ef 100644 --- a/FastImageCache/FICImageFormat.h +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageFormat.h @@ -15,17 +15,17 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatDevices) { FICImageFormatDevicePad = 1 << UIUserInterfaceIdiomPad, }; -typedef NS_OPTIONS(NSUInteger, FICImageFormatStyle) { +typedef NS_ENUM(NSUInteger, FICImageFormatStyle) { FICImageFormatStyle32BitBGRA, FICImageFormatStyle32BitBGR, FICImageFormatStyle16BitBGR, FICImageFormatStyle8BitGrayscale, }; -typedef NS_OPTIONS(NSUInteger, FICImageFormatProtectionMode) { +typedef NS_ENUM(NSUInteger, FICImageFormatProtectionMode) { FICImageFormatProtectionModeNone, FICImageFormatProtectionModeComplete, - FICImageFormatProtectionModeCompletUntilFirstUserAuthentication, + FICImageFormatProtectionModeCompleteUntilFirstUserAuthentication, }; /** @@ -34,6 +34,7 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatProtectionMode) { prevent the image cache from consuming too much disk space. Each `` managed by the image cache is associated with a single image format. */ +NS_ASSUME_NONNULL_BEGIN @interface FICImageFormat : NSObject ///------------------------------ @@ -42,6 +43,9 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatProtectionMode) { /** The name of the image format. Each image format must have a unique name. + + @note Since multiple instances of Fast Image Cache can exist in the same application, it is important that image format name's be unique across all instances of ``. Reverse DNS naming + is recommended (e.g., com.path.PTUserProfilePhotoLargeImageFormat). */ @property (nonatomic, copy) NSString *name; @@ -120,16 +124,36 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatProtectionMode) { */ @property (nonatomic, assign, readonly) BOOL isGrayscale; - +/** + The data protection mode that image table files will be created with. + + `FICImageFormatProtectionMode` has the following values: + + - `FICImageFormatProtectionModeNone`: No data protection is used. The image table file backing this image format will always be available for reading and writing. + - `FICImageFormatProtectionModeComplete`: Complete data protection is used. As soon as the system enables data protection (i.e., when the device is locked), the image table file backing this image + format will not be available for reading and writing. As a result, images of this format should not be requested by Fast Image Cache when executing backgrounded code. + - `FICImageFormatProtectionModeCompleteUntilFirstUserAuthentication`: Partial data protection is used. After a device restart, until the user unlocks the device for the first time, complete data + protection is in effect. However, after the device has been unlocked for the first time, the image table file backing this image format will remain available for readin and writing. This mode may be + a good compromise between encrypting image table files after the device powers down and allowing the files to be accessed successfully by Fast Image Cache, whether or not the device is subsequently + locked. + + @note Data protection can prevent Fast Image Cache from accessing its image table files to read and write image data. If the image data being stored in Fast Image Cache is not sensitive in nature, + consider using `FICImageFormatProtectionModeNone` to prevent any issues accessing image table files when the disk is encrypted. + */ @property (nonatomic, assign) FICImageFormatProtectionMode protectionMode; + +/** + The string representation of ``. + */ @property (nonatomic, assign, readonly) NSString *protectionModeString; /** The dictionary representation of this image format. - @discussion Fast Image Cache automatically serializes the image formats that it uses to disk. If an image format ever changes, Fast Image Cache automatically detects the change and invalidates the image table associated with that image format. The image table is then recreated from the updated image format. + @discussion Fast Image Cache automatically serializes the image formats that it uses to disk. If an image format ever changes, Fast Image Cache automatically detects the change and invalidates the + image table associated with that image format. The image table is then recreated from the updated image format. */ -@property (nonatomic, copy, readonly) NSDictionary *dictionaryRepresentation; +@property (nonatomic, copy, readonly) NSDictionary *dictionaryRepresentation; ///----------------------------------- /// @name Initializing an Image Format @@ -150,8 +174,11 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatProtectionMode) { @param devices A bitmask of type `` that defines which devices are managed by an image table. - @return An autoreleased instance of `` or one of its subclasses, if any exist. + @param protectionMode The data protection mode to use when creating the backing image table file for this image format. See the `` property description for more information. + + @return An autoreleased instance of `FICImageFormat` or one of its subclasses, if any exist. */ + (instancetype)formatWithName:(NSString *)name family:(NSString *)family imageSize:(CGSize)imageSize style:(FICImageFormatStyle)style maximumCount:(NSInteger)maximumCount devices:(FICImageFormatDevices)devices protectionMode:(FICImageFormatProtectionMode)protectionMode; @end +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/FastImageCache/FICImageFormat.m b/FastImageCache/FastImageCache/FastImageCache/FICImageFormat.m similarity index 98% rename from FastImageCache/FICImageFormat.m rename to FastImageCache/FastImageCache/FastImageCache/FICImageFormat.m index ef2a5f8..da6eeca 100644 --- a/FastImageCache/FICImageFormat.m +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageFormat.m @@ -136,7 +136,7 @@ - (NSString *)protectionModeString { case FICImageFormatProtectionModeComplete: protectionModeString = NSFileProtectionComplete; break; - case FICImageFormatProtectionModeCompletUntilFirstUserAuthentication: + case FICImageFormatProtectionModeCompleteUntilFirstUserAuthentication: protectionModeString = NSFileProtectionCompleteUntilFirstUserAuthentication; break; } diff --git a/FastImageCache/FICImageTable.h b/FastImageCache/FastImageCache/FastImageCache/FICImageTable.h similarity index 87% rename from FastImageCache/FICImageTable.h rename to FastImageCache/FastImageCache/FastImageCache/FICImageTable.h index 1c03cb2..c4f542e 100644 --- a/FastImageCache/FICImageTable.h +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageTable.h @@ -15,6 +15,8 @@ @class FICImageTableEntry; @class FICImage; +NS_ASSUME_NONNULL_BEGIN + extern NSString *const FICImageTableEntryDataVersionKey; extern NSString *const FICImageTableScreenScaleKey; @@ -75,11 +77,15 @@ extern NSString *const FICImageTableScreenScaleKey; @param imageFormat The image format that describes the image table. + @param imageCache The instance of `` that owns this image table. + @return A new image table. @warning `FICImageTable` raises an exception if `imageFormat` is `nil`. `FICImageTable`'s implementation of `-init` simply calls through to this initializer, passing `nil` for `imageFormat`. */ -- (instancetype)initWithFormat:(FICImageFormat *)imageFormat imageCache:(FICImageCache *)imageCache; +- (nullable instancetype)initWithFormat:(FICImageFormat *)imageFormat imageCache:(FICImageCache *)imageCache NS_DESIGNATED_INITIALIZER; +-(instancetype) init __attribute__((unavailable("Invoke the designated initializer initWithFormat:imageCache: instead"))); ++(instancetype) new __attribute__((unavailable("Invoke the designated initializer initWithFormat:imageCache: instead"))); ///------------------------------------------------ /// @name Storing, Retrieving, and Deleting Entries @@ -110,16 +116,18 @@ extern NSString *const FICImageTableScreenScaleKey; @param sourceImageUUID The UUID of the source image that represents the actual image data stored in an image table entry. Must not be `nil`. + @param preheatData A `BOOL` indicating whether or not the entry's image data should be preheated. See `<[FICImageTableEntry preheat]>` for more information. + @return A new image created from the entry data stored in the image table or `nil` if something went wrong. @discussion The `UIImage` returned by this method is initialized by a `CGImageRef` backed directly by mapped file data, so no memory copy occurs. - @note If either of the parameters to this method are `nil`, the return value is `nil`. + @note If either of the first two parameters to this method are `nil`, the return value is `nil`. @note If either the entity UUID or the source image UUID doesn't match the corresponding UUIDs in the entry data, then something has changed. The entry data is deleted for the provided entity UUID, and `nil` is returned. */ -- (UIImage *)newImageForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSString *)sourceImageUUID preheatData:(BOOL)preheatData; +- (nullable UIImage *)newImageForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSString *)sourceImageUUID preheatData:(BOOL)preheatData; /** Deletes image entry data in the image table. @@ -160,3 +168,5 @@ extern NSString *const FICImageTableScreenScaleKey; - (void)reset; @end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/FastImageCache/FICImageTable.m b/FastImageCache/FastImageCache/FastImageCache/FICImageTable.m similarity index 83% rename from FastImageCache/FICImageTable.m rename to FastImageCache/FastImageCache/FastImageCache/FICImageTable.m index 0102bc9..2925c02 100644 --- a/FastImageCache/FICImageTable.m +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageTable.m @@ -12,6 +12,7 @@ #import "FICImageTableChunk.h" #import "FICImageTableEntry.h" #import "FICUtilities.h" +#import #import "FICImageCache+FICErrorLogging.h" @@ -62,10 +63,14 @@ @interface FICImageTable () { NSMutableOrderedSet *_MRUEntries; NSCountedSet *_inUseEntries; NSDictionary *_imageFormatDictionary; - - BOOL _isFileDataProtected; + int32_t _metadataVersion; + + NSString *_fileDataProtectionMode; + BOOL _canAccessData; } -@property(nonatomic, weak) FICImageCache *imageCache; + +@property (nonatomic, weak) FICImageCache *imageCache; + @end #pragma mark @@ -78,18 +83,26 @@ @implementation FICImageTable - (NSString *)tableFilePath { NSString *tableFilePath = [[_imageFormat name] stringByAppendingPathExtension:FICImageTableFileExtension]; - tableFilePath = [[FICImageTable directoryPath] stringByAppendingPathComponent:tableFilePath]; + tableFilePath = [[self directoryPath] stringByAppendingPathComponent:tableFilePath]; return tableFilePath; } - (NSString *)metadataFilePath { NSString *metadataFilePath = [[_imageFormat name] stringByAppendingPathExtension:FICImageTableMetadataFileExtension]; - metadataFilePath = [[FICImageTable directoryPath] stringByAppendingPathComponent:metadataFilePath]; + metadataFilePath = [[self directoryPath] stringByAppendingPathComponent:metadataFilePath]; return metadataFilePath; } +- (NSString *) directoryPath { + NSString *directoryPath = [FICImageTable directoryPath]; + if (self.imageCache.nameSpace) { + directoryPath = [directoryPath stringByAppendingPathComponent:self.imageCache.nameSpace]; + } + return directoryPath; +} + #pragma mark - Class-Level Definitions + (int)pageSize { @@ -164,7 +177,15 @@ - (instancetype)initWithFormat:(FICImageFormat *)imageFormat imageCache:(FICImag [self _loadMetadata]; + NSString *directoryPath = [self directoryPath]; + NSFileManager *fileManager = [[NSFileManager alloc] init]; + + BOOL isDirectory; + if (self.imageCache.nameSpace && ![fileManager fileExistsAtPath:directoryPath isDirectory:&isDirectory]) { + [fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:nil]; + } + if ([fileManager fileExistsAtPath:_filePath] == NO) { NSMutableDictionary *attributes = [NSMutableDictionary dictionary]; [attributes setValue:[_imageFormat protectionModeString] forKeyPath:NSFileProtectionKey]; @@ -172,10 +193,7 @@ - (instancetype)initWithFormat:(FICImageFormat *)imageFormat imageCache:(FICImag } NSDictionary *attributes = [fileManager attributesOfItemAtPath:_filePath error:NULL]; - NSString *protectionMode = [attributes objectForKey:NSFileProtectionKey]; - if (protectionMode) { - _isFileDataProtected = [protectionMode isEqualToString:NSFileProtectionNone] == NO; - } + _fileDataProtectionMode = [attributes objectForKey:NSFileProtectionKey]; _fileDescriptor = open([_filePath fileSystemRepresentation], O_RDWR | O_CREAT, 0666); @@ -189,7 +207,7 @@ - (instancetype)initWithFormat:(FICImageFormat *)imageFormat imageCache:(FICImag NSInteger goalEntriesPerChunk = goalChunkLength / _entryLength; _entriesPerChunk = MAX(4, goalEntriesPerChunk); if ([self _maximumCount] > [_imageFormat maximumCount]) { - NSString *message = [NSString stringWithFormat:@"*** FIC Warning: growing desired maximumCount (%ld) for format %@ to fill a chunk (%d)", (long)[_imageFormat maximumCount], [_imageFormat name], [self _maximumCount]]; + NSString *message = [NSString stringWithFormat:@"*** FIC Warning: growing desired maximumCount (%ld) for format %@ to fill a chunk (%ld)", (long)[_imageFormat maximumCount], [_imageFormat name], (long)[self _maximumCount]]; [self.imageCache _logMessage:message]; } _chunkLength = (size_t)(_entryLength * _entriesPerChunk); @@ -215,10 +233,6 @@ - (instancetype)initWithFormat:(FICImageFormat *)imageFormat imageCache:(FICImag return self; } -- (instancetype)init { - return [self initWithFormat:nil imageCache:nil]; -} - - (void)dealloc { if (_fileDescriptor >= 0) { close(_fileDescriptor); @@ -347,8 +361,8 @@ - (UIImage *)newImageForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSStr if (entryData != nil) { NSString *entryEntityUUID = FICStringWithUUIDBytes([entryData entityUUIDBytes]); NSString *entrySourceImageUUID = FICStringWithUUIDBytes([entryData sourceImageUUIDBytes]); - BOOL entityUUIDIsCorrect = entityUUID == nil || [entityUUID isEqualToString:entryEntityUUID]; - BOOL sourceImageUUIDIsCorrect = sourceImageUUID == nil || [sourceImageUUID isEqualToString:entrySourceImageUUID]; + BOOL entityUUIDIsCorrect = entityUUID == nil || [entityUUID caseInsensitiveCompare:entryEntityUUID] == NSOrderedSame; + BOOL sourceImageUUIDIsCorrect = sourceImageUUID == nil || [sourceImageUUID caseInsensitiveCompare:entrySourceImageUUID] == NSOrderedSame; NSNumber *indexNumber = [self _numberForEntryAtIndex:[entryData index]]; @synchronized(indexNumber) { @@ -414,15 +428,16 @@ - (void)deleteEntryForEntityUUID:(NSString *)entityUUID { if (entityUUID != nil) { [_lock lock]; + NSInteger MRUIndex = [_MRUEntries indexOfObject:entityUUID]; + if (MRUIndex != NSNotFound) { + [_MRUEntries removeObjectAtIndex:MRUIndex]; + } + NSInteger index = [self _indexOfEntryForEntityUUID:entityUUID]; if (index != NSNotFound) { [_sourceImageMap removeObjectForKey:entityUUID]; [_indexMap removeObjectForKey:entityUUID]; [_occupiedIndexes removeIndex:index]; - NSInteger index = [_MRUEntries indexOfObject:entityUUID]; - if (index != NSNotFound) { - [_MRUEntries removeObjectAtIndex:index]; - } [self saveMetadata]; } @@ -461,8 +476,8 @@ - (BOOL)entryExistsForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSStrin #pragma mark - Working with Entries -- (int)_maximumCount { - return (int)MAX([_imageFormat maximumCount], _entriesPerChunk); +- (NSInteger)_maximumCount { + return MAX([_imageFormat maximumCount], _entriesPerChunk); } - (void)_setEntryCount:(NSInteger)entryCount { @@ -495,11 +510,29 @@ - (void)_setEntryCount:(NSInteger)entryCount { // accessible and when you try to use that data. Sidestep this issue altogether // by using NSFileProtectionNone - (BOOL)canAccessEntryData { - BOOL result = YES; - if (_isFileDataProtected) { - result = [[UIApplication sharedApplication] isProtectedDataAvailable]; + if ([_fileDataProtectionMode isEqualToString:NSFileProtectionNone]) + return YES; + + if ([_fileDataProtectionMode isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication] && _canAccessData) + return YES; + + // -[UIApplication isProtectedDataAvailable] checks whether the keybag is locked or not + UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)]; + if (application) { + _canAccessData = [application isProtectedDataAvailable]; } - return result; + + // We have to fallback to a direct check on the file if either: + // - The application doesn't exist (happens in some extensions) + // - The keybag is locked, but the file might still be accessible because the mode is "until first user authentication" + if (!application || (!_canAccessData && [_fileDataProtectionMode isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication])) { + int fd; + _canAccessData = ((fd = open([_filePath fileSystemRepresentation], O_RDONLY)) != -1); + if (_canAccessData) + close(fd); + } + + return _canAccessData; } - (FICImageTableEntry *)_entryDataAtIndex:(NSInteger)index { @@ -577,7 +610,7 @@ - (NSInteger)_nextEntryIndex { } if (index >= [self _maximumCount]) { - NSString *message = [NSString stringWithFormat:@"FICImageTable - unable to evict entry from table '%@' to make room. New index %ld, desired max %d", [_imageFormat name], (long)index, [self _maximumCount]]; + NSString *message = [NSString stringWithFormat:@"FICImageTable - unable to evict entry from table '%@' to make room. New index %ld, desired max %ld", [_imageFormat name], (long)index, (long)[self _maximumCount]]; [self.imageCache _logMessage:message]; } @@ -648,36 +681,61 @@ - (NSNumber *)_numberForEntryAtIndex:(NSInteger)index { #pragma mark - Working with Metadata - (void)saveMetadata { - [_lock lock]; - - NSDictionary *metadataDictionary = [NSDictionary dictionaryWithObjectsAndKeys: - [_indexMap copy], FICImageTableIndexMapKey, - [_sourceImageMap copy], FICImageTableContextMapKey, - [[_MRUEntries array] copy], FICImageTableMRUArrayKey, - [_imageFormatDictionary copy], FICImageTableFormatKey, nil]; - [_lock unlock]; - - static dispatch_queue_t __metadataQueue = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - __metadataQueue = dispatch_queue_create("com.path.FastImageCache.ImageTableMetadataQueue", NULL); - }); - - dispatch_async(__metadataQueue, ^{ - NSData *data = [NSPropertyListSerialization dataWithPropertyList:metadataDictionary format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL]; - BOOL fileWriteResult = [data writeToFile:[self metadataFilePath] atomically:NO]; - if (fileWriteResult == NO) { - NSString *message = [NSString stringWithFormat:@"*** FIC Error: %s couldn't write metadata for format %@", __PRETTY_FUNCTION__, [_imageFormat name]]; - [self.imageCache _logMessage:message]; - } - }); + @autoreleasepool { + [_lock lock]; + + NSDictionary *metadataDictionary = [NSDictionary dictionaryWithObjectsAndKeys: + [_indexMap copy], FICImageTableIndexMapKey, + [_sourceImageMap copy], FICImageTableContextMapKey, + [[_MRUEntries array] copy], FICImageTableMRUArrayKey, + [_imageFormatDictionary copy], FICImageTableFormatKey, nil]; + + __block int32_t metadataVersion = OSAtomicIncrement32(&_metadataVersion); + + [_lock unlock]; + + static dispatch_queue_t __metadataQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __metadataQueue = dispatch_queue_create("com.path.FastImageCache.ImageTableMetadataQueue", NULL); + }); + + dispatch_async(__metadataQueue, ^{ + // Cancel serialization if a new metadata version is queued to be saved + if (metadataVersion != _metadataVersion) { + return; + } + + @autoreleasepool { + NSData *data = [NSJSONSerialization dataWithJSONObject:metadataDictionary options:kNilOptions error:NULL]; + + // Cancel disk writing if a new metadata version is queued to be saved + if (metadataVersion != _metadataVersion) { + return; + } + + BOOL fileWriteResult = [data writeToFile:[self metadataFilePath] atomically:NO]; + if (fileWriteResult == NO) { + NSString *message = [NSString stringWithFormat:@"*** FIC Error: %s couldn't write metadata for format %@", __PRETTY_FUNCTION__, [_imageFormat name]]; + [self.imageCache _logMessage:message]; + } + } + }); + } } - (void)_loadMetadata { - NSString *metadataFilePath = [[_filePath stringByDeletingPathExtension] stringByAppendingPathExtension:FICImageTableMetadataFileExtension]; - NSData *metadataData = [NSData dataWithContentsOfMappedFile:metadataFilePath]; + NSString *metadataFilePath = [self metadataFilePath]; + NSData *metadataData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:metadataFilePath] options:NSDataReadingMappedAlways error:NULL]; if (metadataData != nil) { - NSDictionary *metadataDictionary = (NSDictionary *)[NSPropertyListSerialization propertyListWithData:metadataData options:0 format:NULL error:NULL]; + NSDictionary *metadataDictionary = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:metadataData options:kNilOptions error:NULL]; + + if (!metadataDictionary) { + // The image table was likely previously stored as a .plist + // We'll read it into memory as a .plist and later store it (during -saveMetadata) using NSJSONSerialization for performance reasons + metadataDictionary = (NSDictionary *)[NSPropertyListSerialization propertyListWithData:metadataData options:0 format:NULL error:NULL]; + } + NSDictionary *formatDictionary = [metadataDictionary objectForKey:FICImageTableFormatKey]; if ([formatDictionary isEqualToDictionary:_imageFormatDictionary] == NO) { // Something about this image format has changed, so the existing metadata is no longer valid. The image table file diff --git a/FastImageCache/FICImageTableChunk.h b/FastImageCache/FastImageCache/FastImageCache/FICImageTableChunk.h similarity index 86% rename from FastImageCache/FICImageTableChunk.h rename to FastImageCache/FastImageCache/FastImageCache/FICImageTableChunk.h index b5b8664..60fd8c5 100644 --- a/FastImageCache/FICImageTableChunk.h +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageTableChunk.h @@ -8,6 +8,8 @@ #import "FICImports.h" +NS_ASSUME_NONNULL_BEGIN + @class FICImageTable; /** @@ -36,6 +38,9 @@ */ @property (nonatomic, assign, readonly) off_t fileOffset; +/** + The length, in bytes, of the chunk. + */ @property (nonatomic, assign, readonly) size_t length; @@ -54,6 +59,8 @@ @return A new image table chunk. */ -- (instancetype)initWithFileDescriptor:(int)fileDescriptor index:(NSInteger)index length:(size_t)length; +- (nullable instancetype)initWithFileDescriptor:(int)fileDescriptor index:(NSInteger)index length:(size_t)length; + +@end -@end \ No newline at end of file +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/FastImageCache/FICImageTableChunk.m b/FastImageCache/FastImageCache/FastImageCache/FICImageTableChunk.m similarity index 100% rename from FastImageCache/FICImageTableChunk.m rename to FastImageCache/FastImageCache/FastImageCache/FICImageTableChunk.m diff --git a/FastImageCache/FICImageTableEntry.h b/FastImageCache/FastImageCache/FastImageCache/FICImageTableEntry.h similarity index 72% rename from FastImageCache/FICImageTableEntry.h rename to FastImageCache/FastImageCache/FastImageCache/FICImageTableEntry.h index c3771c3..2b8e8d9 100644 --- a/FastImageCache/FICImageTableEntry.h +++ b/FastImageCache/FastImageCache/FastImageCache/FICImageTableEntry.h @@ -8,6 +8,8 @@ #import "FICImports.h" +NS_ASSUME_NONNULL_BEGIN + @class FICImageTableChunk; @class FICImageCache; @@ -53,17 +55,24 @@ typedef struct { */ @property (nonatomic, assign) CFUUIDBytes sourceImageUUIDBytes; +/** + The image table chunk that contains this entry. + */ @property (nonatomic, readonly) FICImageTableChunk *imageTableChunk; +/** + A weak reference to the image cache that contains the image table chunk that contains this entry. + */ @property (nonatomic, weak) FICImageCache *imageCache; +/** + The index where this entry exists in the image table. + */ @property (nonatomic, assign) NSInteger index; -- (void)preheat; - -///---------------------------------------- -/// @name Initializing an Image Table Entry -///---------------------------------------- +///---------------------------------- +/// @name Image Table Entry Lifecycle +///---------------------------------- /** Initializes a new image table entry from an image table chunk. @@ -76,10 +85,22 @@ typedef struct { @return A new image table entry. */ -- (instancetype)initWithImageTableChunk:(FICImageTableChunk *)imageTableChunk bytes:(void *)bytes length:(size_t)length; +- (nullable instancetype)initWithImageTableChunk:(FICImageTableChunk *)imageTableChunk bytes:(void *)bytes length:(size_t)length; +/** + Adds a block to be executed when this image table entry is deallocated. + + @param block A block that will be called when this image table entry is deallocated. + + @note Because of the highly-concurrent nature of Fast Image Cache, image tables must know when any of their entries are about to be deallocated to disassociate them with its internal data structures. + */ - (void)executeBlockOnDealloc:(dispatch_block_t)block; +/** + Forces the kernel to page in the memory-mapped, on-disk data backing this entry right away. + */ +- (void)preheat; + ///-------------------------------------------- /// @name Flushing a Modified Image Table Entry ///-------------------------------------------- @@ -103,3 +124,5 @@ typedef struct { + (NSInteger)metadataVersion; @end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/FastImageCache/FICImageTableEntry.m b/FastImageCache/FastImageCache/FastImageCache/FICImageTableEntry.m similarity index 100% rename from FastImageCache/FICImageTableEntry.m rename to FastImageCache/FastImageCache/FastImageCache/FICImageTableEntry.m diff --git a/FastImageCache/FICImports.h b/FastImageCache/FastImageCache/FastImageCache/FICImports.h similarity index 100% rename from FastImageCache/FICImports.h rename to FastImageCache/FastImageCache/FastImageCache/FICImports.h diff --git a/FastImageCache/FastImageCache/FastImageCache/FICUtilities.h b/FastImageCache/FastImageCache/FastImageCache/FICUtilities.h new file mode 100644 index 0000000..62c6abe --- /dev/null +++ b/FastImageCache/FastImageCache/FastImageCache/FICUtilities.h @@ -0,0 +1,17 @@ +// +// FICUtilities.h +// FastImageCache +// +// Copyright (c) 2013 Path, Inc. +// See LICENSE for full license agreement. +// + +#import "FICImports.h" + +size_t FICByteAlign(size_t bytesPerRow, size_t alignment); +size_t FICByteAlignForCoreAnimation(size_t bytesPerRow); + +NSString * _Nullable FICStringWithUUIDBytes(CFUUIDBytes UUIDBytes); +CFUUIDBytes FICUUIDBytesWithString(NSString * _Nonnull string); +CFUUIDBytes FICUUIDBytesFromMD5HashOfString(NSString * _Nonnull MD5Hash); // Useful for computing an entity's UUID from a URL, for example + diff --git a/FastImageCache/FICUtilities.m b/FastImageCache/FastImageCache/FastImageCache/FICUtilities.m similarity index 100% rename from FastImageCache/FICUtilities.m rename to FastImageCache/FastImageCache/FastImageCache/FICUtilities.m diff --git a/FastImageCache/FastImageCache/Info.plist b/FastImageCache/FastImageCache/Info.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/FastImageCache/FastImageCache/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/Contents.json b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/Contents.json similarity index 95% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/Contents.json rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/Contents.json index 6fb4d76..2e6e194 100644 --- a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/Contents.json +++ b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/Contents.json @@ -33,6 +33,11 @@ "filename" : "iPhone-App-iOS7@2x.png", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, { "idiom" : "ipad", "size" : "29x29", diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App-iOS7.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App-iOS7.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App-iOS7.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App-iOS7.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App-iOS7@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App-iOS7@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App-iOS7@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App-iOS7@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPad-App@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPad-App@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPhone-App-iOS7@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPhone-App-iOS7@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPhone-App-iOS7@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPhone-App-iOS7@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPhone-App.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPhone-App.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPhone-App.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPhone-App.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPhone-App@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPhone-App@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Icon.appiconset/iPhone-App@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Icon.appiconset/iPhone-App@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/Contents.json b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/Contents.json similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/Contents.json rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/Contents.json diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-1004h@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPad-Portrait-iOS7@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x-1.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x-1.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x-1.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x-1.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-R4@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-iOS7@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-iOS7@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-iOS7@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait-iOS7@2x.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait.png diff --git a/FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait@2x.png b/FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait@2x.png similarity index 100% rename from FastImageCacheDemo/Supporting Files/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait@2x.png rename to FastImageCache/FastImageCacheDemo/Assets.xcassets/Launch Image.launchimage/iPhone-Portrait@2x.png diff --git a/FastImageCacheDemo/Classes/FICDAppDelegate.h b/FastImageCache/FastImageCacheDemo/Classes/FICDAppDelegate.h similarity index 93% rename from FastImageCacheDemo/Classes/FICDAppDelegate.h rename to FastImageCache/FastImageCacheDemo/Classes/FICDAppDelegate.h index e946626..51e41f3 100644 --- a/FastImageCacheDemo/Classes/FICDAppDelegate.h +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDAppDelegate.h @@ -6,6 +6,8 @@ // See LICENSE for full license agreement. // +#import + @class FICDViewController; @interface FICDAppDelegate : UIResponder diff --git a/FastImageCacheDemo/Classes/FICDAppDelegate.m b/FastImageCache/FastImageCacheDemo/Classes/FICDAppDelegate.m similarity index 100% rename from FastImageCacheDemo/Classes/FICDAppDelegate.m rename to FastImageCache/FastImageCacheDemo/Classes/FICDAppDelegate.m diff --git a/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.h b/FastImageCache/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.h similarity index 96% rename from FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.h rename to FastImageCache/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.h index 821f7f8..2ccc662 100644 --- a/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.h +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.h @@ -6,6 +6,9 @@ // See LICENSE for full license agreement. // +#import +#import + @class FICDPhoto; @protocol FICDFullscreenPhotoDisplayControllerDelegate; diff --git a/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.m b/FastImageCache/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.m similarity index 100% rename from FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.m rename to FastImageCache/FastImageCacheDemo/Classes/FICDFullscreenPhotoDisplayController.m diff --git a/FastImageCacheDemo/Classes/FICDPhoto.h b/FastImageCache/FastImageCacheDemo/Classes/FICDPhoto.h similarity index 100% rename from FastImageCacheDemo/Classes/FICDPhoto.h rename to FastImageCache/FastImageCacheDemo/Classes/FICDPhoto.h diff --git a/FastImageCacheDemo/Classes/FICDPhoto.m b/FastImageCache/FastImageCacheDemo/Classes/FICDPhoto.m similarity index 88% rename from FastImageCacheDemo/Classes/FICDPhoto.m rename to FastImageCache/FastImageCacheDemo/Classes/FICDPhoto.m index d0df261..b169cad 100644 --- a/FastImageCacheDemo/Classes/FICDPhoto.m +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDPhoto.m @@ -13,11 +13,11 @@ NSString *const FICDPhotoImageFormatFamily = @"FICDPhotoImageFormatFamily"; -NSString *const FICDPhotoSquareImage32BitBGRAFormatName = @"FICDPhotoSquareImage32BitBGRAFormatName"; -NSString *const FICDPhotoSquareImage32BitBGRFormatName = @"FICDPhotoSquareImage32BitBGRFormatName"; -NSString *const FICDPhotoSquareImage16BitBGRFormatName = @"FICDPhotoSquareImage16BitBGRFormatName"; -NSString *const FICDPhotoSquareImage8BitGrayscaleFormatName = @"FICDPhotoSquareImage8BitGrayscaleFormatName"; -NSString *const FICDPhotoPixelImageFormatName = @"FICDPhotoPixelImageFormatName"; +NSString *const FICDPhotoSquareImage32BitBGRAFormatName = @"com.path.FastImageCacheDemo.FICDPhotoSquareImage32BitBGRAFormatName"; +NSString *const FICDPhotoSquareImage32BitBGRFormatName = @"com.path.FastImageCacheDemo.FICDPhotoSquareImage32BitBGRFormatName"; +NSString *const FICDPhotoSquareImage16BitBGRFormatName = @"com.path.FastImageCacheDemo.FICDPhotoSquareImage16BitBGRFormatName"; +NSString *const FICDPhotoSquareImage8BitGrayscaleFormatName = @"com.path.FastImageCacheDemo.FICDPhotoSquareImage8BitGrayscaleFormatName"; +NSString *const FICDPhotoPixelImageFormatName = @"com.path.FastImageCacheDemo.FICDPhotoPixelImageFormatName"; CGSize const FICDPhotoSquareImageSize = {75, 75}; CGSize const FICDPhotoPixelImageSize = {1, 1}; @@ -167,25 +167,26 @@ - (void)deleteThumbnail { #pragma mark - FICImageCacheEntity -- (NSString *)UUID { +- (NSString *)fic_UUID { if (_UUID == nil) { // MD5 hashing is expensive enough that we only want to do it once - CFUUIDBytes UUIDBytes = FICUUIDBytesFromMD5HashOfString([_sourceImageURL absoluteString]); + NSString *imageName = [_sourceImageURL lastPathComponent]; + CFUUIDBytes UUIDBytes = FICUUIDBytesFromMD5HashOfString(imageName); _UUID = FICStringWithUUIDBytes(UUIDBytes); } return _UUID; } -- (NSString *)sourceImageUUID { - return [self UUID]; +- (NSString *)fic_sourceImageUUID { + return [self fic_UUID]; } -- (NSURL *)sourceImageURLWithFormatName:(NSString *)formatName { +- (NSURL *)fic_sourceImageURLWithFormatName:(NSString *)formatName { return _sourceImageURL; } -- (FICEntityImageDrawingBlock)drawingBlockForImage:(UIImage *)image withFormatName:(NSString *)formatName { +- (FICEntityImageDrawingBlock)fic_drawingBlockForImage:(UIImage *)image withFormatName:(NSString *)formatName { FICEntityImageDrawingBlock drawingBlock = ^(CGContextRef contextRef, CGSize contextSize) { CGRect contextBounds = CGRectZero; contextBounds.size = contextSize; diff --git a/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.h b/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.h similarity index 89% rename from FastImageCacheDemo/Classes/FICDPhotosTableViewCell.h rename to FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.h index a925b6d..11d3b07 100644 --- a/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.h +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.h @@ -6,6 +6,8 @@ // See LICENSE for full license agreement. // +#import + @class FICDPhoto; @protocol FICDPhotosTableViewCellDelegate; @@ -20,7 +22,7 @@ + (NSString *)reuseIdentifier; + (NSInteger)photosPerRow; + (CGFloat)outerPadding; -+ (CGFloat)rowHeightForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; ++ (CGFloat)rowHeight; @end diff --git a/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m b/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m similarity index 70% rename from FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m rename to FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m index cf35c31..5c7c29d 100644 --- a/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m @@ -19,7 +19,7 @@ @interface FICDPhotosTableViewCell () { NSArray *_photos; NSString *_imageFormatName; - NSMutableArray *_imageViews; + NSArray *_imageViews; UITapGestureRecognizer *_tapGestureRecognizer; } @@ -39,42 +39,28 @@ @implementation FICDPhotosTableViewCell - (void)setPhotos:(NSArray *)photos { if (photos != _photos) { _photos = [photos copy]; - - // Either create the image views for this cell or clear them out if they already exist - if (_imageViews == nil) { - NSInteger photosPerRow = [[self class] photosPerRow]; - _imageViews = [[NSMutableArray alloc] initWithCapacity:photosPerRow]; - - for (NSInteger i = 0; i < photosPerRow; i++) { - UIImageView *imageView = [[UIImageView alloc] init]; - [imageView setContentMode:UIViewContentModeScaleAspectFill]; - [_imageViews addObject:imageView]; - } - } else { - for (UIImageView *imageView in _imageViews) { - [imageView setImage:nil]; - [imageView removeFromSuperview]; - } - } - - NSInteger photosCount = [_photos count]; - for (NSInteger i = 0; i < photosCount; i++) { - FICDPhoto *photo = [_photos objectAtIndex:i]; + + for (NSInteger i = 0; i < [_imageViews count]; i++) { UIImageView *imageView = [_imageViews objectAtIndex:i]; - - if (_usesImageTable) { - [[FICImageCache sharedImageCache] retrieveImageForEntity:photo withFormatName:_imageFormatName completionBlock:^(id entity, NSString *formatName, UIImage *image) { - // This completion block may be called much later. We should check to make sure this cell hasn't been reused for different photos before displaying the image that has loaded. - if (photos == [self photos]) { - [imageView setImage:image]; - } - }]; + + if (i < [_photos count]) { + FICDPhoto *photo = [_photos objectAtIndex:i]; + + if (_usesImageTable) { + [[FICImageCache sharedImageCache] retrieveImageForEntity:photo withFormatName:_imageFormatName completionBlock:^(id entity, NSString *formatName, UIImage *image) { + // This completion block may be called much later. We should check to make sure this cell hasn't been reused for different photos before displaying the image that has loaded. + if (photos == [self photos]) { + [imageView setImage:image]; + } + }]; + } else { + [imageView setImage:[photo thumbnailImage]]; + } } else { - [imageView setImage:[photo thumbnailImage]]; + // Last row might not be full + [imageView setImage:nil]; } } - - [self setNeedsLayout]; } } @@ -103,7 +89,7 @@ + (CGFloat)outerPadding { return outerPadding; } -+ (CGFloat)rowHeightForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { ++ (CGFloat)rowHeight { CGFloat rowHeight = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) ? 84 : 79; return rowHeight; @@ -117,6 +103,18 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus if (self != nil) { _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_tapGestureRecognizerStateDidChange)]; [self addGestureRecognizer:_tapGestureRecognizer]; + + NSInteger photosPerRow = [[self class] photosPerRow]; + NSMutableArray *imageViews = [[NSMutableArray alloc] initWithCapacity:photosPerRow]; + + for (NSInteger i = 0; i < photosPerRow; i++) { + UIImageView *imageView = [[UIImageView alloc] init]; + [imageView setContentMode:UIViewContentModeScaleAspectFill]; + [imageViews addObject:imageView]; + [self.contentView addSubview:imageView]; + } + + _imageViews = [imageViews copy]; } return self; @@ -139,14 +137,12 @@ - (void)layoutSubviews { CGFloat outerPadding = [[self class] outerPadding]; CGRect imageViewFrame = CGRectMake(outerPadding, outerPadding, FICDPhotoSquareImageSize.width, FICDPhotoSquareImageSize.height); - - UIView *contentView = [self contentView]; + NSInteger count = [_photos count]; for (NSInteger i = 0; i < count; i++) { UIImageView *imageView = [_imageViews objectAtIndex:i]; [imageView setFrame:imageViewFrame]; - [contentView addSubview:imageView]; imageViewFrame.origin.x += imageViewFrame.size.width + innerPadding; } diff --git a/FastImageCacheDemo/Classes/FICDTableView.h b/FastImageCache/FastImageCacheDemo/Classes/FICDTableView.h similarity index 91% rename from FastImageCacheDemo/Classes/FICDTableView.h rename to FastImageCache/FastImageCacheDemo/Classes/FICDTableView.h index 500fec9..14e8b39 100644 --- a/FastImageCacheDemo/Classes/FICDTableView.h +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDTableView.h @@ -6,6 +6,8 @@ // See LICENSE for full license agreement. // +#import + @interface FICDTableView : UITableView @property (nonatomic, assign, readonly) CGFloat averageFPS; diff --git a/FastImageCacheDemo/Classes/FICDTableView.m b/FastImageCache/FastImageCacheDemo/Classes/FICDTableView.m similarity index 100% rename from FastImageCacheDemo/Classes/FICDTableView.m rename to FastImageCache/FastImageCacheDemo/Classes/FICDTableView.m diff --git a/FastImageCacheDemo/Classes/FICDViewController.h b/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.h similarity index 89% rename from FastImageCacheDemo/Classes/FICDViewController.h rename to FastImageCache/FastImageCacheDemo/Classes/FICDViewController.h index 54f3023..0cbe5fb 100644 --- a/FastImageCacheDemo/Classes/FICDViewController.h +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.h @@ -6,6 +6,8 @@ // See LICENSE for full license agreement. // +#import + @class FICDTableView; @interface FICDViewController : UIViewController diff --git a/FastImageCacheDemo/Classes/FICDViewController.m b/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m similarity index 96% rename from FastImageCacheDemo/Classes/FICDViewController.m rename to FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m index 3495167..c81c8bd 100644 --- a/FastImageCacheDemo/Classes/FICDViewController.m +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m @@ -95,6 +95,7 @@ - (void)loadView { [_tableView setDelegate:self]; [_tableView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; [_tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + [_tableView registerClass:[FICDPhotosTableViewCell class] forCellReuseIdentifier:[FICDPhotosTableViewCell reuseIdentifier]]; CGFloat tableViewCellOuterPadding = [FICDPhotosTableViewCell outerPadding]; [_tableView setContentInset:UIEdgeInsetsMake(0, 0, tableViewCellOuterPadding, 0)]; @@ -110,13 +111,12 @@ - (void)loadView { // Configure the navigation item UINavigationItem *navigationItem = [self navigationItem]; - UIBarButtonItem *resetBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Reset" style:UIBarButtonItemStyleBordered target:self action:@selector(_reset)]; + UIBarButtonItem *resetBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Reset" style:UIBarButtonItemStylePlain target:self action:@selector(_reset)]; [navigationItem setLeftBarButtonItem:resetBarButtonItem]; UISegmentedControl *methodSegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Conventional", @"Image Table", nil]]; [methodSegmentedControl setSelectedSegmentIndex:0]; [methodSegmentedControl addTarget:self action:@selector(_methodSegmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged]; - [methodSegmentedControl setSegmentedControlStyle:UISegmentedControlStyleBar]; [methodSegmentedControl sizeToFit]; [navigationItem setTitleView:methodSegmentedControl]; @@ -152,7 +152,6 @@ - (void)loadView { UISegmentedControl *imageFormatStyleSegmentedControl = [[UISegmentedControl alloc] initWithItems:imageFormatStyleSegmentedControlTitles]; [imageFormatStyleSegmentedControl setSelectedSegmentIndex:0]; [imageFormatStyleSegmentedControl addTarget:self action:@selector(_imageFormatStyleSegmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged]; - [imageFormatStyleSegmentedControl setSegmentedControlStyle:UISegmentedControlStyleBar]; [imageFormatStyleSegmentedControl setApportionsSegmentWidthsByContent:userInterfaceIdiomIsPhone]; [imageFormatStyleSegmentedControl sizeToFit]; @@ -463,13 +462,9 @@ - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger) - (UITableViewCell*)tableView:(UITableView*)table cellForRowAtIndexPath:(NSIndexPath*)indexPath { NSString *reuseIdentifier = [FICDPhotosTableViewCell reuseIdentifier]; - FICDPhotosTableViewCell *tableViewCell = (FICDPhotosTableViewCell *)[table dequeueReusableCellWithIdentifier:reuseIdentifier]; - if (tableViewCell == nil) { - tableViewCell = [[FICDPhotosTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; - [tableViewCell setBackgroundColor:[table backgroundColor]]; - [tableViewCell setSelectionStyle:UITableViewCellSelectionStyleNone]; - } - + FICDPhotosTableViewCell *tableViewCell = (FICDPhotosTableViewCell *)[table dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath]; + tableViewCell.selectionStyle = UITableViewCellSeparatorStyleNone; + [tableViewCell setDelegate:self]; [tableViewCell setImageFormatName:_imageFormatName]; @@ -487,9 +482,7 @@ - (UITableViewCell*)tableView:(UITableView*)table cellForRowAtIndexPath:(NSIndex #pragma mark - UITableViewDelegate - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - CGFloat rowHeight = [FICDPhotosTableViewCell rowHeightForInterfaceOrientation:[self interfaceOrientation]]; - - return rowHeight; + return [FICDPhotosTableViewCell rowHeight]; } - (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { @@ -553,7 +546,7 @@ - (void)photoDisplayController:(FICDFullscreenPhotoDisplayController *)photoDisp [self _updateStatusBarStyleForColorAveragedImage:colorAveragedImage]; } } else { - [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES]; + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES]; } } diff --git a/FastImageCacheDemo/Demo Images/README b/FastImageCache/FastImageCacheDemo/Demo Images/README similarity index 100% rename from FastImageCacheDemo/Demo Images/README rename to FastImageCache/FastImageCacheDemo/Demo Images/README diff --git a/FastImageCacheDemo/Supporting Files/FastImageCacheDemo-Prefix.pch b/FastImageCache/FastImageCacheDemo/FastImageCacheDemo-Prefix.pch similarity index 100% rename from FastImageCacheDemo/Supporting Files/FastImageCacheDemo-Prefix.pch rename to FastImageCache/FastImageCacheDemo/FastImageCacheDemo-Prefix.pch diff --git a/FastImageCacheDemo/Supporting Files/FastImageCacheDemo-Info.plist b/FastImageCache/FastImageCacheDemo/Info.plist similarity index 69% rename from FastImageCacheDemo/Supporting Files/FastImageCacheDemo-Info.plist rename to FastImageCache/FastImageCacheDemo/Info.plist index b48b80f..eabb3ae 100644 --- a/FastImageCacheDemo/Supporting Files/FastImageCacheDemo-Info.plist +++ b/FastImageCache/FastImageCacheDemo/Info.plist @@ -4,20 +4,14 @@ CFBundleDevelopmentRegion en - CFBundleDisplayName - FIC Demo CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIcons - - CFBundleIcons~ipad - + $(EXECUTABLE_NAME) CFBundleIdentifier - com.path.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString @@ -25,27 +19,27 @@ CFBundleSignature ???? CFBundleVersion - 1.0 + 1 LSRequiresIPhoneOS + UILaunchStoryboardName + LaunchScreen UIRequiredDeviceCapabilities armv7 - UIStatusBarHidden - - UIStatusBarHidden~ipad - UISupportedInterfaceOrientations UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - diff --git a/FastImageCacheDemo/fetch_demo_images.sh b/FastImageCache/FastImageCacheDemo/fetch_demo_images.sh similarity index 100% rename from FastImageCacheDemo/fetch_demo_images.sh rename to FastImageCache/FastImageCacheDemo/fetch_demo_images.sh diff --git a/FastImageCacheDemo/Supporting Files/main.m b/FastImageCache/FastImageCacheDemo/main.m similarity index 57% rename from FastImageCacheDemo/Supporting Files/main.m rename to FastImageCache/FastImageCacheDemo/main.m index 3d5d2d3..0f2990b 100644 --- a/FastImageCacheDemo/Supporting Files/main.m +++ b/FastImageCache/FastImageCacheDemo/main.m @@ -2,13 +2,14 @@ // main.m // FastImageCacheDemo // -// Copyright (c) 2013 Path, Inc. -// See LICENSE for full license agreement. +// Created by Rui Peres on 17/06/2015. +// Copyright (c) 2015 Path. All rights reserved. // +#import #import "FICDAppDelegate.h" -int main(int argc, char *argv[]) { +int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([FICDAppDelegate class])); } diff --git a/FastImageCache/FastImageCacheTests/FastImageCacheTests.m b/FastImageCache/FastImageCacheTests/FastImageCacheTests.m new file mode 100644 index 0000000..8a16cdb --- /dev/null +++ b/FastImageCache/FastImageCacheTests/FastImageCacheTests.m @@ -0,0 +1,40 @@ +// +// FastImageCacheTests.m +// FastImageCacheTests +// +// Created by Rui Peres on 17/06/2015. +// Copyright (c) 2015 Path. All rights reserved. +// + +#import +#import + +@interface FastImageCacheTests : XCTestCase + +@end + +@implementation FastImageCacheTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + XCTAssert(YES, @"Pass"); +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/FastImageCache/FastImageCacheTests/Info.plist b/FastImageCache/FastImageCacheTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/FastImageCache/FastImageCacheTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/FastImageCacheDemo/FastImageCacheDemo.xcodeproj/project.pbxproj b/FastImageCacheDemo/FastImageCacheDemo.xcodeproj/project.pbxproj deleted file mode 100644 index 8decd75..0000000 --- a/FastImageCacheDemo/FastImageCacheDemo.xcodeproj/project.pbxproj +++ /dev/null @@ -1,380 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 2E095B1417AEBB1200ECE160 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E095B1317AEBB1200ECE160 /* UIKit.framework */; }; - 2E095B1617AEBB1200ECE160 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E095B1517AEBB1200ECE160 /* Foundation.framework */; }; - 2E1BC8F017C57C4700836A7E /* FICImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8E417C57C4700836A7E /* FICImageCache.m */; }; - 2E1BC8F117C57C4700836A7E /* FICImageFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8E617C57C4700836A7E /* FICImageFormat.m */; }; - 2E1BC8F217C57C4700836A7E /* FICImageTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8E817C57C4700836A7E /* FICImageTable.m */; }; - 2E1BC8F317C57C4700836A7E /* FICImageTableChunk.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8EA17C57C4700836A7E /* FICImageTableChunk.m */; }; - 2E1BC8F417C57C4700836A7E /* FICImageTableEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8EC17C57C4700836A7E /* FICImageTableEntry.m */; }; - 2E1BC8FE17C57CDF00836A7E /* FICDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8F717C57CD300836A7E /* FICDAppDelegate.m */; }; - 2E1BC8FF17C57CDF00836A7E /* FICDPhoto.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8F917C57CD300836A7E /* FICDPhoto.m */; }; - 2E1BC90017C57CDF00836A7E /* FICDPhotosTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8FB17C57CD300836A7E /* FICDPhotosTableViewCell.m */; }; - 2E1BC90117C57CDF00836A7E /* FICDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8FD17C57CD300836A7E /* FICDViewController.m */; }; - 2E64541017FF24C0001D0531 /* FICDTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E64540F17FF24C0001D0531 /* FICDTableView.m */; }; - 2EA7994417B2A10200684B86 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA7993F17B2A10200684B86 /* main.m */; }; - EB171332181F089F00EB0E24 /* CoreImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB171331181F089F00EB0E24 /* CoreImage.framework */; }; - EB642D8017DCB1750013D644 /* FICDFullscreenPhotoDisplayController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB642D7F17DCB1750013D644 /* FICDFullscreenPhotoDisplayController.m */; }; - EB6BD53818079DAB00D762CE /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB6BD53718079DAB00D762CE /* CoreGraphics.framework */; }; - EB6BD53A18079EA800D762CE /* FICUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E1BC8EE17C57C4700836A7E /* FICUtilities.m */; }; - EBB922BD17DA8E6A00211050 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBB922BC17DA8E6A00211050 /* QuartzCore.framework */; }; - EBB922BF17DC08E900211050 /* Demo Images in Resources */ = {isa = PBXBuildFile; fileRef = EBB922BE17DC08E900211050 /* Demo Images */; }; - EBC8A5F217FF6DEF007FECD4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EBC8A5F117FF6DEF007FECD4 /* Assets.xcassets */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 2E095B1017AEBB1200ECE160 /* FastImageCacheDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FastImageCacheDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 2E095B1317AEBB1200ECE160 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 2E095B1517AEBB1200ECE160 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 2E1BC8E317C57C4700836A7E /* FICImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageCache.h; sourceTree = ""; }; - 2E1BC8E417C57C4700836A7E /* FICImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageCache.m; sourceTree = ""; }; - 2E1BC8E517C57C4700836A7E /* FICImageFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageFormat.h; sourceTree = ""; }; - 2E1BC8E617C57C4700836A7E /* FICImageFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageFormat.m; sourceTree = ""; }; - 2E1BC8E717C57C4700836A7E /* FICImageTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageTable.h; sourceTree = ""; }; - 2E1BC8E817C57C4700836A7E /* FICImageTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageTable.m; sourceTree = ""; }; - 2E1BC8E917C57C4700836A7E /* FICImageTableChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageTableChunk.h; sourceTree = ""; }; - 2E1BC8EA17C57C4700836A7E /* FICImageTableChunk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageTableChunk.m; sourceTree = ""; }; - 2E1BC8EB17C57C4700836A7E /* FICImageTableEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICImageTableEntry.h; sourceTree = ""; }; - 2E1BC8EC17C57C4700836A7E /* FICImageTableEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICImageTableEntry.m; sourceTree = ""; }; - 2E1BC8ED17C57C4700836A7E /* FICUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICUtilities.h; sourceTree = ""; }; - 2E1BC8EE17C57C4700836A7E /* FICUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICUtilities.m; sourceTree = ""; }; - 2E1BC8F617C57CD300836A7E /* FICDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FICDAppDelegate.h; sourceTree = ""; }; - 2E1BC8F717C57CD300836A7E /* FICDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FICDAppDelegate.m; sourceTree = ""; }; - 2E1BC8F817C57CD300836A7E /* FICDPhoto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FICDPhoto.h; sourceTree = ""; }; - 2E1BC8F917C57CD300836A7E /* FICDPhoto.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FICDPhoto.m; sourceTree = ""; }; - 2E1BC8FA17C57CD300836A7E /* FICDPhotosTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FICDPhotosTableViewCell.h; sourceTree = ""; }; - 2E1BC8FB17C57CD300836A7E /* FICDPhotosTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FICDPhotosTableViewCell.m; sourceTree = ""; }; - 2E1BC8FC17C57CD300836A7E /* FICDViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FICDViewController.h; sourceTree = ""; }; - 2E1BC8FD17C57CD300836A7E /* FICDViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FICDViewController.m; sourceTree = ""; }; - 2E64540E17FF24C0001D0531 /* FICDTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDTableView.h; sourceTree = ""; }; - 2E64540F17FF24C0001D0531 /* FICDTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDTableView.m; sourceTree = ""; }; - 2EA7993F17B2A10200684B86 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - EB171331181F089F00EB0E24 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; }; - EB642D3717DC9C690013D644 /* FastImageCacheDemo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "FastImageCacheDemo-Info.plist"; sourceTree = ""; }; - EB642D7E17DCB1750013D644 /* FICDFullscreenPhotoDisplayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FICDFullscreenPhotoDisplayController.h; sourceTree = ""; }; - EB642D7F17DCB1750013D644 /* FICDFullscreenPhotoDisplayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FICDFullscreenPhotoDisplayController.m; sourceTree = ""; }; - EB6BD53718079DAB00D762CE /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - EB6BD53918079E2D00D762CE /* FICImports.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FICImports.h; sourceTree = ""; }; - EBB922BA17D8EC7F00211050 /* FastImageCacheDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FastImageCacheDemo-Prefix.pch"; sourceTree = ""; }; - EBB922BC17DA8E6A00211050 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - EBB922BE17DC08E900211050 /* Demo Images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Demo Images"; sourceTree = ""; }; - EBC8A5F117FF6DEF007FECD4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - EBC8A63718036430007FECD4 /* FICEntity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FICEntity.h; sourceTree = ""; }; - EBC8A6381804B63A007FECD4 /* FICImageCache+FICErrorLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FICImageCache+FICErrorLogging.h"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 2E095B0D17AEBB1200ECE160 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EB6BD53818079DAB00D762CE /* CoreGraphics.framework in Frameworks */, - EB171332181F089F00EB0E24 /* CoreImage.framework in Frameworks */, - EBB922BD17DA8E6A00211050 /* QuartzCore.framework in Frameworks */, - 2E095B1417AEBB1200ECE160 /* UIKit.framework in Frameworks */, - 2E095B1617AEBB1200ECE160 /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2E095B0717AEBB1200ECE160 = { - isa = PBXGroup; - children = ( - 2E1BC8E017C57C4700836A7E /* FastImageCache */, - 2EA7993A17B2A0CF00684B86 /* Demo App */, - 2E095B1217AEBB1200ECE160 /* Frameworks */, - 2E095B1117AEBB1200ECE160 /* Products */, - ); - sourceTree = ""; - }; - 2E095B1117AEBB1200ECE160 /* Products */ = { - isa = PBXGroup; - children = ( - 2E095B1017AEBB1200ECE160 /* FastImageCacheDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - 2E095B1217AEBB1200ECE160 /* Frameworks */ = { - isa = PBXGroup; - children = ( - EB6BD53718079DAB00D762CE /* CoreGraphics.framework */, - EB171331181F089F00EB0E24 /* CoreImage.framework */, - 2E095B1517AEBB1200ECE160 /* Foundation.framework */, - EBB922BC17DA8E6A00211050 /* QuartzCore.framework */, - 2E095B1317AEBB1200ECE160 /* UIKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 2E095B1A17AEBB1200ECE160 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - EBC8A5F117FF6DEF007FECD4 /* Assets.xcassets */, - 2EA7993F17B2A10200684B86 /* main.m */, - EBB922BA17D8EC7F00211050 /* FastImageCacheDemo-Prefix.pch */, - EB642D3717DC9C690013D644 /* FastImageCacheDemo-Info.plist */, - ); - path = "Supporting Files"; - sourceTree = ""; - }; - 2E1BC8E017C57C4700836A7E /* FastImageCache */ = { - isa = PBXGroup; - children = ( - EBC8A63718036430007FECD4 /* FICEntity.h */, - EBC8A6381804B63A007FECD4 /* FICImageCache+FICErrorLogging.h */, - 2E1BC8E317C57C4700836A7E /* FICImageCache.h */, - 2E1BC8E417C57C4700836A7E /* FICImageCache.m */, - 2E1BC8E517C57C4700836A7E /* FICImageFormat.h */, - 2E1BC8E617C57C4700836A7E /* FICImageFormat.m */, - 2E1BC8E717C57C4700836A7E /* FICImageTable.h */, - 2E1BC8E817C57C4700836A7E /* FICImageTable.m */, - 2E1BC8E917C57C4700836A7E /* FICImageTableChunk.h */, - 2E1BC8EA17C57C4700836A7E /* FICImageTableChunk.m */, - 2E1BC8EB17C57C4700836A7E /* FICImageTableEntry.h */, - 2E1BC8EC17C57C4700836A7E /* FICImageTableEntry.m */, - EB6BD53918079E2D00D762CE /* FICImports.h */, - 2E1BC8ED17C57C4700836A7E /* FICUtilities.h */, - 2E1BC8EE17C57C4700836A7E /* FICUtilities.m */, - ); - name = FastImageCache; - path = ../FastImageCache; - sourceTree = ""; - }; - 2EA7993A17B2A0CF00684B86 /* Demo App */ = { - isa = PBXGroup; - children = ( - EB642D3917DC9D970013D644 /* Classes */, - EBB922BE17DC08E900211050 /* Demo Images */, - 2E095B1A17AEBB1200ECE160 /* Supporting Files */, - ); - name = "Demo App"; - sourceTree = ""; - }; - EB642D3917DC9D970013D644 /* Classes */ = { - isa = PBXGroup; - children = ( - 2E1BC8F617C57CD300836A7E /* FICDAppDelegate.h */, - 2E1BC8F717C57CD300836A7E /* FICDAppDelegate.m */, - EB642D7E17DCB1750013D644 /* FICDFullscreenPhotoDisplayController.h */, - EB642D7F17DCB1750013D644 /* FICDFullscreenPhotoDisplayController.m */, - 2E1BC8F817C57CD300836A7E /* FICDPhoto.h */, - 2E1BC8F917C57CD300836A7E /* FICDPhoto.m */, - 2E1BC8FA17C57CD300836A7E /* FICDPhotosTableViewCell.h */, - 2E1BC8FB17C57CD300836A7E /* FICDPhotosTableViewCell.m */, - 2E64540E17FF24C0001D0531 /* FICDTableView.h */, - 2E64540F17FF24C0001D0531 /* FICDTableView.m */, - 2E1BC8FC17C57CD300836A7E /* FICDViewController.h */, - 2E1BC8FD17C57CD300836A7E /* FICDViewController.m */, - ); - path = Classes; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 2E095B0F17AEBB1200ECE160 /* FastImageCacheDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2E095B3617AEBB1200ECE160 /* Build configuration list for PBXNativeTarget "FastImageCacheDemo" */; - buildPhases = ( - 2E095B0C17AEBB1200ECE160 /* Sources */, - 2E095B0D17AEBB1200ECE160 /* Frameworks */, - 2E095B0E17AEBB1200ECE160 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = FastImageCacheDemo; - productName = "Image Cache"; - productReference = 2E095B1017AEBB1200ECE160 /* FastImageCacheDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 2E095B0817AEBB1200ECE160 /* Project object */ = { - isa = PBXProject; - attributes = { - CLASSPREFIX = PT; - LastUpgradeCheck = 0460; - ORGANIZATIONNAME = Path; - }; - buildConfigurationList = 2E095B0B17AEBB1200ECE160 /* Build configuration list for PBXProject "FastImageCacheDemo" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 2E095B0717AEBB1200ECE160; - productRefGroup = 2E095B1117AEBB1200ECE160 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 2E095B0F17AEBB1200ECE160 /* FastImageCacheDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 2E095B0E17AEBB1200ECE160 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EBB922BF17DC08E900211050 /* Demo Images in Resources */, - EBC8A5F217FF6DEF007FECD4 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 2E095B0C17AEBB1200ECE160 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2EA7994417B2A10200684B86 /* main.m in Sources */, - 2E1BC8F017C57C4700836A7E /* FICImageCache.m in Sources */, - 2E1BC8F117C57C4700836A7E /* FICImageFormat.m in Sources */, - 2E1BC8F217C57C4700836A7E /* FICImageTable.m in Sources */, - EB642D8017DCB1750013D644 /* FICDFullscreenPhotoDisplayController.m in Sources */, - EB6BD53A18079EA800D762CE /* FICUtilities.m in Sources */, - 2E1BC8F317C57C4700836A7E /* FICImageTableChunk.m in Sources */, - 2E1BC8F417C57C4700836A7E /* FICImageTableEntry.m in Sources */, - 2E64541017FF24C0001D0531 /* FICDTableView.m in Sources */, - 2E1BC8FE17C57CDF00836A7E /* FICDAppDelegate.m in Sources */, - 2E1BC8FF17C57CDF00836A7E /* FICDPhoto.m in Sources */, - 2E1BC90017C57CDF00836A7E /* FICDPhotosTableViewCell.m in Sources */, - 2E1BC90117C57CDF00836A7E /* FICDViewController.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 2E095B3417AEBB1200ECE160 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = NO; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = fast; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 2E095B3517AEBB1200ECE160 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = NO; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 2E095B3717AEBB1200ECE160 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = Icon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Launch Image"; - "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Supporting Files/FastImageCacheDemo-Prefix.pch"; - INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/FastImageCacheDemo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; - PRODUCT_NAME = FastImageCacheDemo; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 2E095B3817AEBB1200ECE160 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = Icon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Launch Image"; - "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Supporting Files/FastImageCacheDemo-Prefix.pch"; - INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/FastImageCacheDemo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; - PRODUCT_NAME = FastImageCacheDemo; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 2E095B0B17AEBB1200ECE160 /* Build configuration list for PBXProject "FastImageCacheDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2E095B3417AEBB1200ECE160 /* Debug */, - 2E095B3517AEBB1200ECE160 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2E095B3617AEBB1200ECE160 /* Build configuration list for PBXNativeTarget "FastImageCacheDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2E095B3717AEBB1200ECE160 /* Debug */, - 2E095B3817AEBB1200ECE160 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 2E095B0817AEBB1200ECE160 /* Project object */; -} diff --git a/README.md b/README.md index 260f1b1..6a6654c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ![Fast Image Cache Logo](https://s3.amazonaws.com/fast-image-cache/readme-resources/logo.png) --- +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) Fast Image Cache is an efficient, persistent, and—above all—fast way to store and retrieve images in your iOS application. Part of any good iOS application's user experience is fast, smooth scrolling, and Fast Image Cache helps make this easier. @@ -31,6 +32,7 @@ A significant burden on performance for graphics-rich applications like [Path](h - [**1.0**](https://github.com/path/FastImageCache/releases/tag/1.0) (10/18/2013): Initial release - [**1.1**](https://github.com/path/FastImageCache/releases/tag/1.1) (10/22/2013): Added ARC support and more robust Core Animation byte alignment - [**1.2**](https://github.com/path/FastImageCache/releases/tag/1.2) (10/30/2013): Added support for image format styles and canceling image requests +- [**1.3**](https://github.com/path/FastImageCache/releases/tag/1.3) (03/30/2014): Significant bug fixes and performance improvements ## What Fast Image Cache Does @@ -72,7 +74,7 @@ Consider the workflow that occurs when loading an image from disk and displaying 1 `60FPS` ≈ `0.01666s per frame` = `16.7ms per frame`. This means that any main-thread work that takes longer than 16ms will cause your application to drop animation frames. -2 The documentation for [`CALayer`](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CCwQFjAA&url=https%3A%2F%2Fdeveloper.apple.com%2Flibrary%2Fios%2Fdocumentation%2Fgraphicsimaging%2Freference%2FCALayer_class%2FIntroduction%2FIntroduction.html&ei=P29XUpj2LeahiALptICgCQ&usg=AFQjCNGwJuHcQV4593kuookUcvNZYTvx5w&sig2=zi1audY4ZsNE_xLeESVD_Q)'s [`contents`](https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CALayer_class/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004500-CH1-SW24) property states that "assigning a value to this property causes the layer to use your image rather than [creating] a separate backing store." However, the meaning of "use your image" is still vague. Profiling an application using [Instruments](https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004652-CH1-SW1) often reveals calls to `CA::Render::copy_image`, even when the Core Animation Instrument has indicated that none of the images have been copied. One reason that Core Animation will require a copy of an image is improper [byte alignment](#byte-alignment). +2 The documentation for [`CALayer`](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CCwQFjAA&url=https%3A%2F%2Fdeveloper.apple.com%2Flibrary%2Fios%2Fdocumentation%2Fgraphicsimaging%2Freference%2FCALayer_class%2FIntroduction%2FIntroduction.html&ei=P29XUpj2LeahiALptICgCQ&usg=AFQjCNGwJuHcQV4593kuookUcvNZYTvx5w&sig2=zi1audY4ZsNE_xLeESVD_Q)'s [`contents`](https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CALayer_class/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004500-CH1-SW24) property states that "assigning a value to this property causes the layer to use your image rather than [creating] a separate backing store." However, the meaning of "use your image" is still vague. Profiling an application using [Instruments](https://developer.apple.com/library/prerelease/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/) often reveals calls to `CA::Render::copy_image`, even when the Core Animation Instrument has indicated that none of the images have been copied. One reason that Core Animation will require a copy of an image is improper [byte alignment](#byte-alignment). 3 As of iOS 7, Apple does not make their hardware JPEG decoder available for third-party applications to use. As a result, only a slower, software decoder is used for this step. @@ -128,6 +130,12 @@ For example, if an original image is resized by an entity to create a thumbnail Image format families can be specified to efficiently make use of a single source image. See [Working with Image Format Families](#working-with-image-format-families) for more information. +### Data Protection + +In iOS 4, Apple introduced data protection. When a user's device is locked or turned off, the disk is encrypted. Files written to disk are protected by default, although applications can manually specify the data protection mode for each file it manages. With the advent of new background modes in iOS 7, applications can now execute in the background briefly even while the device is locked. As a result, data protection can cause issues if applications attempt to access files that are encrypted. + +Fast Image Cache allows each image format to specify the data protection mode used when creating its backing image table file. Be aware that enabling data protection for image table files means that Fast Image Cache might not be able to read or write image data from or to these files when the disk is encrypted. + ## Requirements Fast Image Cache requires iOS 6.0 or greater and relies on the following frameworks: @@ -154,8 +162,8 @@ For easy project integration, Fast Image Cache is available as a [CocoaPod](http - Clone this repository, or [download the latest archive of `master`](https://github.com/path/FastImageCache/archive/master.zip). - From the `FastImageCache` root directory, copy the source files from the inner [`FastImageCache`](./FastImageCache) subdirectory to your Xcode project. -- Import [`FICImageCache.h`](./FastImageCache/FICImageCache.h) wherever you use the image cache. -- Import [`FICEntity.h`](./FastImageCache/FICEntity.h) for each class that conforms to [`FICEntity`](https://s3.amazonaws.com/fast-image-cache/documentation/Protocols/FICEntity.html). +- Import [`FICImageCache.h`](./FastImageCache/FastImageCache/FastImageCache/FICImageCache.h) wherever you use the image cache. +- Import [`FICEntity.h`](./FastImageCache/FastImageCache/FastImageCache/FICEntity.h) for each class that conforms to [`FICEntity`](https://s3.amazonaws.com/fast-image-cache/documentation/Protocols/FICEntity.html). ### Initial Configuration @@ -166,6 +174,10 @@ Before the image cache can be used, it needs to be configured. This must occur e Each image format corresponds to an image table that the image cache will use. Image formats that can use the same source image to render the images they store in their image tables should belong to the same [image format family](#working-with-image-format-families). See [Image Table Size](#image-table-size) for more information about how to determine an appropriate maximum count. ```objective-c +static NSString *XXImageFormatNameUserThumbnailSmall = @"com.mycompany.myapp.XXImageFormatNameUserThumbnailSmall"; +static NSString *XXImageFormatNameUserThumbnailMedium = @"com.mycompany.myapp.XXImageFormatNameUserThumbnailMedium"; +static NSString *XXImageFormatFamilyUserThumbnails = @"com.mycompany.myapp.XXImageFormatFamilyUserThumbnails"; + FICImageFormat *smallUserThumbnailImageFormat = [[FICImageFormat alloc] init]; smallUserThumbnailImageFormat.name = XXImageFormatNameUserThumbnailSmall; smallUserThumbnailImageFormat.family = XXImageFormatFamilyUserThumbnails; @@ -173,6 +185,7 @@ smallUserThumbnailImageFormat.style = FICImageFormatStyle16BitBGR; smallUserThumbnailImageFormat.imageSize = CGSizeMake(50, 50); smallUserThumbnailImageFormat.maximumCount = 250; smallUserThumbnailImageFormat.devices = FICImageFormatDevicePhone; +smallUserThumbnailImageFormat.protectionMode = FICImageFormatProtectionModeNone; FICImageFormat *mediumUserThumbnailImageFormat = [[FICImageFormat alloc] init]; mediumUserThumbnailImageFormat.name = XXImageFormatNameUserThumbnailMedium; @@ -181,6 +194,7 @@ mediumUserThumbnailImageFormat.style = FICImageFormatStyle32BitBGRA; mediumUserThumbnailImageFormat.imageSize = CGSizeMake(100, 100); mediumUserThumbnailImageFormat.maximumCount = 250; mediumUserThumbnailImageFormat.devices = FICImageFormatDevicePhone; +mediumUserThumbnailImageFormat.protectionMode = FICImageFormatProtectionModeNone; NSArray *imageFormats = @[smallUserThumbnailImageFormat, mediumUserThumbnailImageFormat]; ``` @@ -365,7 +379,7 @@ When this happens, Fast Image Cache cleans up its internal bookkeeping, and any ### Working with Image Format Families -The advantage of classifying image formats into families is that the image cache's delegate can tell the image cache to process entity source images for **all** image formats in a family when **any** image format in that family is processed. +The advantage of classifying image formats into families is that the image cache's delegate can tell the image cache to process entity source images for **all** image formats in a family when **any** image format in that family is processed. By default, all image formats are processed for a given family unless you implement this delegate and return otherwise. ```objective-c - (BOOL)imageCache:(FICImageCache *)imageCache shouldProcessAllFormatsInFamily:(NSString *)formatFamily forEntity:(id)entity { @@ -394,7 +408,7 @@ HTML documentation can be [found here](https://s3.amazonaws.com/fast-image-cache Included with this repository is a demo app Xcode project. It demonstrates the difference between the conventional approach for loading and displaying images and the Fast Image Cache approach. See the [requirements for running the demo app Xcode project](#requirements). -> **Note**: The demo application must either be supplied with JPEG images, or the included [`fetch_demo_images.sh`](./FastImageCacheDemo/fetch_demo_images.sh) script in the [`FastImageCacheDemo`](./FastImageCacheDemo) directory must be run. +> **Note**: The demo application must either be supplied with JPEG images, or the included [`fetch_demo_images.sh`](./FastImageCache/FastImageCacheDemo/fetch_demo_images.sh) script in the [`FastImageCacheDemo`](./FastImageCache/FastImageCacheDemo) directory must be run. ### Video