diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index c9144df2fb..495d95f8b5 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -252,8 +252,26 @@ 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */; }; 636EA1A41C7FF4EC00EE152F /* NSArray+Diffing.m in Sources */ = {isa = PBXBuildFile; fileRef = DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */; }; 636EA1A51C7FF4EF00EE152F /* ASDefaultPlayButton.m in Sources */ = {isa = PBXBuildFile; fileRef = AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */; }; + 68355B301CB5799E001D4E68 /* ASImageNode+AnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B2D1CB5799E001D4E68 /* ASImageNode+AnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */; }; + 68355B331CB579AD001D4E68 /* ASImageNode+AnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B2D1CB5799E001D4E68 /* ASImageNode+AnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68355B341CB579B9001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */; }; + 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; + 68355B3B1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68355B3C1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */; }; + 68355B3D1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; }; + 68355B3E1CB57A60001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; + 68355B3F1CB57A64001D4E68 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; }; + 68355B401CB57A69001D4E68 /* ASImageContainerProtocolCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */; }; + 68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */; }; 68B0277A1C1A79CC0041016B /* ASDisplayNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68B0277B1C1A79D60041016B /* ASDisplayNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68B8A4DC1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */; }; + 68B8A4E11CBDB958007E4543 /* ASWeakProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */; }; + 68B8A4E21CBDB958007E4543 /* ASWeakProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */; }; + 68B8A4E31CBDB958007E4543 /* ASWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */; }; + 68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */; }; 68EE0DBD1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; @@ -743,7 +761,16 @@ 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASFlowLayoutController.h; sourceTree = ""; }; 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASFlowLayoutController.mm; sourceTree = ""; }; 4640521D1A3F83C40061C0BA /* ASLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutController.h; sourceTree = ""; }; + 68355B2D1CB5799E001D4E68 /* ASImageNode+AnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASImageNode+AnimatedImage.h"; sourceTree = ""; }; + 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASImageNode+AnimatedImage.mm"; sourceTree = ""; }; + 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPINRemoteImageDownloader.m; sourceTree = ""; }; + 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageContainerProtocolCategories.h; sourceTree = ""; }; + 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASImageContainerProtocolCategories.m; sourceTree = ""; }; + 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPINRemoteImageDownloader.h; sourceTree = ""; }; 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+Beta.h"; sourceTree = ""; }; + 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASImageNode+AnimatedImagePrivate.h"; sourceTree = ""; }; + 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakProxy.h; sourceTree = ""; }; + 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASWeakProxy.m; sourceTree = ""; }; 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = ""; }; 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; 698548611CA9E025008A345F /* ASEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironment.h; sourceTree = ""; }; @@ -1023,6 +1050,8 @@ 0587F9BC1A7309ED00AFF0BA /* ASEditableTextNode.mm */, 058D09DD195D050800B7D73C /* ASImageNode.h */, 058D09DE195D050800B7D73C /* ASImageNode.mm */, + 68355B2D1CB5799E001D4E68 /* ASImageNode+AnimatedImage.h */, + 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */, 0516FA3E1A1563D200B4EBED /* ASMultiplexImageNode.h */, 0516FA3F1A1563D200B4EBED /* ASMultiplexImageNode.mm */, 055B9FA61A1C154B00035D6D /* ASNetworkImageNode.h */, @@ -1150,9 +1179,13 @@ 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */, 058D09E6195D050800B7D73C /* ASHighlightOverlayLayer.h */, 058D09E7195D050800B7D73C /* ASHighlightOverlayLayer.mm */, - 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */, 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */, + 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, + 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */, + 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */, + 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */, + 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */, 4640521D1A3F83C40061C0BA /* ASLayoutController.h */, 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */, 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */, @@ -1169,6 +1202,8 @@ 296A0A311A951715005ACEAA /* ASScrollDirection.h */, 205F0E111B371BD7007741D0 /* ASScrollDirection.m */, 058D0A12195D050800B7D73C /* ASThread.h */, + 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */, + 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */, 205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */, 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */, 25B171EA1C12242700508A7A /* Data Controller */, @@ -1226,6 +1261,7 @@ 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */, 058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */, 058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */, + 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */, ACF6ED431B17847A00DA7C62 /* ASInternalHelpers.h */, ACF6ED441B17847A00DA7C62 /* ASInternalHelpers.mm */, ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */, @@ -1407,6 +1443,7 @@ 058D0A6D195D05EC00B7D73C /* _ASAsyncTransactionGroup.h in Headers */, 058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */, 7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */, + 68B8A4DC1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h in Headers */, 058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */, 058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */, B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, @@ -1444,12 +1481,14 @@ ACF6ED201B17843500DA7C62 /* ASDimension.h in Headers */, 058D0A78195D05F900B7D73C /* ASDisplayNode+DebugTiming.h in Headers */, DECBD6E71BE56E1900CF4905 /* ASButtonNode.h in Headers */, + 68B8A4E11CBDB958007E4543 /* ASWeakProxy.h in Headers */, DBC452DB1C5BF64600B16017 /* NSArray+Diffing.h in Headers */, 058D0A4C195D05CB00B7D73C /* ASDisplayNode+Subclasses.h in Headers */, 058D0A4A195D05CB00B7D73C /* ASDisplayNode.h in Headers */, 058D0A84195D060300B7D73C /* ASDisplayNodeExtraIvars.h in Headers */, AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */, 058D0A4D195D05CB00B7D73C /* ASDisplayNodeExtras.h in Headers */, + 68355B3B1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h in Headers */, 68B0277A1C1A79CC0041016B /* ASDisplayNode+Beta.h in Headers */, 767E7F8D1C9019130066C000 /* AsyncDisplayKit+Debug.h in Headers */, 257754B11BEE44CD00737CA5 /* ASTextKitShadower.h in Headers */, @@ -1470,6 +1509,7 @@ ACF6ED221B17843500DA7C62 /* ASInsetLayoutSpec.h in Headers */, ACF6ED4B1B17847A00DA7C62 /* ASInternalHelpers.h in Headers */, DB55C2661C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */, + 68355B3D1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h in Headers */, ACF6ED241B17843500DA7C62 /* ASLayout.h in Headers */, 251B8EFB1BBB3D690087C538 /* ASDataController+Subclasses.h in Headers */, ACF6ED2A1B17843500DA7C62 /* ASLayoutable.h in Headers */, @@ -1500,6 +1540,7 @@ 257754C31BEE458E00737CA5 /* ASTextNodeTypes.h in Headers */, 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */, 69E1006D1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */, + 68355B301CB5799E001D4E68 /* ASImageNode+AnimatedImage.h in Headers */, AC21EC101B3D0BF600C8B19A /* ASStackLayoutDefines.h in Headers */, CC7FD9DE1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */, ACF6ED2F1B17843500DA7C62 /* ASStackLayoutSpec.h in Headers */, @@ -1542,6 +1583,7 @@ B35062481B010EFD0018CF92 /* _AS-objc-internal.h in Headers */, 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */, B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */, + 68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */, 7630FFA81C9E267E007A7C0E /* ASVideoNode.h in Headers */, B350623F1B010EFD0018CF92 /* _ASAsyncTransactionContainer.h in Headers */, B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */, @@ -1563,8 +1605,10 @@ 254C6B731BF94DF4003EC431 /* ASTextKitCoreTextAdditions.h in Headers */, 254C6B7A1BF94DF4003EC431 /* ASTextKitRenderer.h in Headers */, 69CB62AC1CB8165900024920 /* _ASDisplayViewAccessiblity.h in Headers */, + 68355B3F1CB57A64001D4E68 /* ASPINRemoteImageDownloader.h in Headers */, 254C6B7C1BF94DF4003EC431 /* ASTextKitRenderer+TextChecking.h in Headers */, 34EFC7611B701C9C00AD841F /* ASBackgroundLayoutSpec.h in Headers */, + 68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */, B35062591B010F070018CF92 /* ASBaseDefines.h in Headers */, B35062131B010EFD0018CF92 /* ASBasicImageDownloader.h in Headers */, B35062461B010EFD0018CF92 /* ASBasicImageDownloaderInternal.h in Headers */, @@ -1610,10 +1654,12 @@ 34EFC75F1B701C8600AD841F /* ASInsetLayoutSpec.h in Headers */, 34EFC75D1B701BE900AD841F /* ASInternalHelpers.h in Headers */, 34EFC7671B701CD900AD841F /* ASLayout.h in Headers */, + 68355B331CB579AD001D4E68 /* ASImageNode+AnimatedImage.h in Headers */, DEC146B71C37A16A004A0EE7 /* ASCollectionInternal.h in Headers */, DBDB83951C6E879900D0098C /* ASPagerFlowLayout.h in Headers */, 34EFC7691B701CE100AD841F /* ASLayoutable.h in Headers */, 9CDC18CD1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */, + 68B8A4E21CBDB958007E4543 /* ASWeakProxy.h in Headers */, B35062201B010EFD0018CF92 /* ASLayoutController.h in Headers */, B35062211B010EFD0018CF92 /* ASLayoutRangeType.h in Headers */, 34EFC76A1B701CE600AD841F /* ASLayoutSpec.h in Headers */, @@ -1886,13 +1932,16 @@ E55D86321CA8A14000A0C26F /* ASLayoutable.mm in Sources */, 058D0A23195D050800B7D73C /* _ASAsyncTransactionContainer.m in Sources */, 058D0A24195D050800B7D73C /* _ASAsyncTransactionGroup.m in Sources */, + 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */, DBDB83961C6E879900D0098C /* ASPagerFlowLayout.m in Sources */, 058D0A26195D050800B7D73C /* _ASCoreAnimationExtras.mm in Sources */, 257754B41BEE44CD00737CA5 /* ASTextKitTailTruncater.mm in Sources */, + 68B8A4E31CBDB958007E4543 /* ASWeakProxy.m in Sources */, 69E1006F1CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */, AC026B711BD57DBF00BBC17E /* _ASHierarchyChangeSet.m in Sources */, 257754BF1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m in Sources */, 058D0A18195D050800B7D73C /* _ASDisplayLayer.mm in Sources */, + 68355B3C1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m in Sources */, 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */, 058D0A19195D050800B7D73C /* _ASDisplayView.mm in Sources */, 9C55866A1BD549CB00B50E3A /* ASAsciiArtBoxCreator.m in Sources */, @@ -1973,6 +2022,7 @@ 81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */, ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */, AC026B6B1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, + 68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */, 055F1A3519ABD3E3004DAFF1 /* ASTableView.mm in Sources */, 058D0A17195D050800B7D73C /* ASTextNode.mm in Sources */, 257754AC1BEE44CD00737CA5 /* ASTextKitRenderer.mm in Sources */, @@ -2062,6 +2112,7 @@ 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */, + 68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */, 69CB62AE1CB8165900024920 /* _ASDisplayViewAccessiblity.mm in Sources */, B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */, 509E68641B3AEDB7009B9150 /* ASCollectionViewLayoutController.mm in Sources */, @@ -2077,6 +2128,7 @@ DEC146B91C37A16A004A0EE7 /* ASCollectionInternal.m in Sources */, 69E100701CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */, 254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */, + 68355B341CB579B9001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */, E5711A301C840C96009619D4 /* ASIndexedNodeContext.m in Sources */, B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */, B35061FC1B010EFD0018CF92 /* ASDisplayNode.mm in Sources */, @@ -2087,6 +2139,7 @@ B350621C1B010EFD0018CF92 /* ASFlowLayoutController.mm in Sources */, B350621E1B010EFD0018CF92 /* ASHighlightOverlayLayer.mm in Sources */, B35062541B010EFD0018CF92 /* ASImageNode+CGExtras.m in Sources */, + 68355B401CB57A69001D4E68 /* ASImageContainerProtocolCategories.m in Sources */, B35062031B010EFD0018CF92 /* ASImageNode.mm in Sources */, 254C6B821BF94F8A003EC431 /* ASTextKitComponents.m in Sources */, 430E7C921B4C23F100697A4C /* ASIndexPath.m in Sources */, @@ -2123,6 +2176,7 @@ DB78412E1C6BCE1600A9E2B4 /* _ASTransitionContext.m in Sources */, B350620B1B010EFD0018CF92 /* ASTableView.mm in Sources */, B350620E1B010EFD0018CF92 /* ASTextNode.mm in Sources */, + 68355B3E1CB57A60001D4E68 /* ASPINRemoteImageDownloader.m in Sources */, C78F7E2A1BF7808300CDEAFC /* ASTableNode.m in Sources */, 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */, 254C6B8D1BF94F8A003EC431 /* ASEqualityHashHelpers.mm in Sources */, diff --git a/AsyncDisplayKit/ASImageNode+AnimatedImage.h b/AsyncDisplayKit/ASImageNode+AnimatedImage.h new file mode 100644 index 0000000000..9e8126580e --- /dev/null +++ b/AsyncDisplayKit/ASImageNode+AnimatedImage.h @@ -0,0 +1,15 @@ +// +// ASImageNode+AnimatedImage.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASImageNode.h" +#import "ASImageProtocols.h" + +@interface ASImageNode () +@property (atomic, assign) BOOL animatedImagePaused; +@property (nullable, atomic, strong) id animatedImage; +@end diff --git a/AsyncDisplayKit/ASImageNode+AnimatedImage.mm b/AsyncDisplayKit/ASImageNode+AnimatedImage.mm new file mode 100644 index 0000000000..ae296ab608 --- /dev/null +++ b/AsyncDisplayKit/ASImageNode+AnimatedImage.mm @@ -0,0 +1,226 @@ +// +// ASImageNode+AnimatedImage.m +// AsyncDisplayKit +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASImageNode+AnimatedImage.h" + +#import "ASAssert.h" +#import "ASImageProtocols.h" +#import "ASDisplayNode+Subclasses.h" +#import "ASDisplayNodeExtras.h" +#import "ASEqualityHelpers.h" +#import "ASDisplayNode+FrameworkPrivate.h" +#import "ASImageNode+AnimatedImagePrivate.h" +#import "ASInternalHelpers.h" +#import "ASWeakProxy.h" + +@implementation ASImageNode (AnimatedImage) + +#pragma mark - GIF support + +- (void)setAnimatedImage:(id )animatedImage +{ + ASDN::MutexLocker l(_animatedImageLock); + if (!ASObjectIsEqual(_animatedImage, animatedImage)) { + _animatedImage = animatedImage; + } + if (animatedImage != nil) { + __weak ASImageNode *weakSelf = self; + if ([animatedImage respondsToSelector:@selector(setCoverImageReadyCallback:)]) { + animatedImage.coverImageReadyCallback = ^(UIImage *coverImage) { + [weakSelf coverImageCompleted:coverImage]; + }; + } + + animatedImage.playbackReadyCallback = ^{ + [weakSelf animatedImageFileReady]; + }; + } +} + +- (id )animatedImage +{ + ASDN::MutexLocker l(_animatedImageLock); + return _animatedImage; +} + +- (void)setAnimatedImagePaused:(BOOL)animatedImagePaused +{ + ASDN::MutexLocker l(_animatedImagePausedLock); + _animatedImagePaused = animatedImagePaused; + ASPerformBlockOnMainThread(^{ + if (animatedImagePaused) { + [self stopAnimating]; + } else { + [self startAnimating]; + } + }); +} + +- (BOOL)animatedImagePaused +{ + ASDN::MutexLocker l(_animatedImagePausedLock); + return _animatedImagePaused; +} + +- (void)coverImageCompleted:(UIImage *)coverImage +{ + BOOL setCoverImage = YES; + { + ASDN::MutexLocker l(_displayLinkLock); + if (_displayLink != nil && _displayLink.paused == NO) { + setCoverImage = NO; + } + } + + if (setCoverImage) { + self.image = coverImage; + } +} + +- (void)animatedImageFileReady +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self startAnimating]; + }); +} + +- (void)startAnimating +{ + ASDisplayNodeAssertMainThread(); + if (ASInterfaceStateIncludesVisible(self.interfaceState) == NO) { + return; + } + + if (self.animatedImagePaused) { + return; + } + + if (self.animatedImage.playbackReady == NO) { + return; + } + +#if ASAnimatedImageDebug + NSLog(@"starting animation: %p", self); +#endif + ASDN::MutexLocker l(_displayLinkLock); + if (_displayLink == nil) { + _playHead = 0; + _displayLink = [CADisplayLink displayLinkWithTarget:[ASWeakProxy weakProxyWithTarget:self] selector:@selector(displayLinkFired:)]; + _displayLink.frameInterval = self.animatedImage.frameInterval; + + [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; + } else { + _displayLink.paused = NO; + } +} + +- (void)stopAnimating +{ +#if ASAnimatedImageDebug + NSLog(@"stopping animation: %p", self); +#endif + ASDisplayNodeAssertMainThread(); + ASDN::MutexLocker l(_displayLinkLock); + _displayLink.paused = YES; + self.lastDisplayLinkFire = 0; + + [self.animatedImage clearAnimatedImageCache]; +} + +- (void)visibilityDidChange:(BOOL)isVisible +{ + [super visibilityDidChange:isVisible]; + + ASDisplayNodeAssertMainThread(); + if (isVisible) { + if (self.animatedImage.coverImageReady) { + self.image = self.animatedImage.coverImage; + } + [self startAnimating]; + } else { + [self stopAnimating]; + } +} + +- (void)__enterHierarchy +{ + [super __enterHierarchy]; + [self startAnimating]; +} + +- (void)__exitHierarchy +{ + [super __exitHierarchy]; + [self stopAnimating]; +} + +- (void)displayLinkFired:(CADisplayLink *)displayLink +{ + ASDisplayNodeAssertMainThread(); + + CFTimeInterval timeBetweenLastFire; + if (self.lastDisplayLinkFire == 0) { + timeBetweenLastFire = 0; + } else { + timeBetweenLastFire = CACurrentMediaTime() - self.lastDisplayLinkFire; + } + self.lastDisplayLinkFire = CACurrentMediaTime(); + + _playHead += timeBetweenLastFire; + + while (_playHead > self.animatedImage.totalDuration) { + _playHead -= self.animatedImage.totalDuration; + _playedLoops++; + } + + if (self.animatedImage.loopCount > 0 && _playedLoops >= self.animatedImage.loopCount) { + [self stopAnimating]; + return; + } + + NSUInteger frameIndex = [self frameIndexAtPlayHeadPosition:_playHead]; + CGImageRef frameImage = [self.animatedImage imageAtIndex:frameIndex]; + + if (frameImage == nil) { + _playHead -= timeBetweenLastFire; + //Pause the display link until we get a file ready notification + displayLink.paused = YES; + self.lastDisplayLinkFire = 0; + } else { + self.contents = (__bridge id)frameImage; + } +} + +- (NSUInteger)frameIndexAtPlayHeadPosition:(CFTimeInterval)playHead +{ + ASDisplayNodeAssertMainThread(); + NSUInteger frameIndex = 0; + for (NSUInteger durationIndex = 0; durationIndex < self.animatedImage.frameCount; durationIndex++) { + playHead -= [self.animatedImage durationAtIndex:durationIndex]; + if (playHead < 0) { + return frameIndex; + } + frameIndex++; + } + + return frameIndex; +} + +- (void)dealloc +{ + ASDN::MutexLocker l(_displayLinkLock); +#if ASAnimatedImageDebug + if (_displayLink) { + NSLog(@"invalidating display link"); + } +#endif + [_displayLink invalidate]; + _displayLink = nil; +} + +@end diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index 3ab12e565a..104463dab9 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -16,6 +16,8 @@ #import #import #import +#import +#import #import "ASImageNode+CGExtras.h" #import "AsyncDisplayKit+Debug.h" diff --git a/AsyncDisplayKit/ASMultiplexImageNode.mm b/AsyncDisplayKit/ASMultiplexImageNode.mm index 351ff9c7d9..b7d0c915b0 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.mm +++ b/AsyncDisplayKit/ASMultiplexImageNode.mm @@ -738,8 +738,8 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent if (_cache) { if (_cacheSupportsNewProtocol) { - [_cache cachedImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() completion:^(UIImage *imageFromCache) { - completionBlock(imageFromCache); + [_cache cachedImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() completion:^(id imageContainer) { + completionBlock([imageContainer asdk_image]); }]; } else { #pragma clang diagnostic push @@ -784,7 +784,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent [self _setDownloadIdentifier:[_downloader downloadImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() downloadProgress:downloadProgressBlock - completion:^(UIImage *downloadedImage, NSError *error, id downloadIdentifier) { + completion:^(id imageContainer, NSError *error, id downloadIdentifier) { // We dereference iVars directly, so we can't have weakSelf going nil on us. __typeof__(self) strongSelf = weakSelf; if (!strongSelf) @@ -796,7 +796,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent return; } - completionBlock(downloadedImage, error); + completionBlock([imageContainer asdk_image], error); // Delegateify. if (strongSelf->_delegateFlags.downloadFinish) diff --git a/AsyncDisplayKit/ASNetworkImageNode.mm b/AsyncDisplayKit/ASNetworkImageNode.mm index f909de9f82..6a8e37cbdb 100755 --- a/AsyncDisplayKit/ASNetworkImageNode.mm +++ b/AsyncDisplayKit/ASNetworkImageNode.mm @@ -14,6 +14,8 @@ #import "ASEqualityHelpers.h" #import "ASThread.h" #import "ASInternalHelpers.h" +#import "ASImageContainerProtocolCategories.h" +#import "ASImageNode+AnimatedImage.h" #if PIN_REMOTE_IMAGE #import "ASPINRemoteImageDownloader.h" @@ -46,6 +48,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; BOOL _downloaderSupportsNewProtocol; BOOL _downloaderImplementsSetProgress; BOOL _downloaderImplementsSetPriority; + BOOL _downloaderImplementsAnimatedImage; BOOL _cacheSupportsNewProtocol; BOOL _cacheSupportsClearing; @@ -71,6 +74,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; _downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)]; _downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)]; + _downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)]; _cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)]; _cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)]; @@ -188,7 +192,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; if (_cacheSupportsSynchronousFetch) { ASDN::MutexLocker l(_lock); if (_imageLoaded == NO && _URL && _downloadIdentifier == nil) { - UIImage *result = [_cache synchronouslyFetchedCachedImageWithURL:_URL]; + UIImage *result = [[_cache synchronouslyFetchedCachedImageWithURL:_URL] asdk_image]; if (result) { self.image = result; _imageLoaded = YES; @@ -291,6 +295,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; image = nil; }); } + self.animatedImage = nil; self.image = _defaultImage; _imageLoaded = NO; } @@ -309,7 +314,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; _cacheUUID = nil; } -- (void)_downloadImageWithCompletion:(void (^)(UIImage *image, NSError*, id downloadIdentifier))finished +- (void)_downloadImageWithCompletion:(void (^)(id imageContainer, NSError*, id downloadIdentifier))finished { ASPerformBlockOnBackgroundThread(^{ ASDN::MutexLocker l(_lock); @@ -317,9 +322,9 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; _downloadIdentifier = [_downloader downloadImageWithURL:_URL callbackQueue:dispatch_get_main_queue() downloadProgress:NULL - completion:^(UIImage * _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier) { + completion:^(id _Nullable imageContainer, NSError * _Nullable error, id _Nullable downloadIdentifier) { if (finished != NULL) { - finished(image, error, downloadIdentifier); + finished(imageContainer, error, downloadIdentifier); } }]; } else { @@ -376,7 +381,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; } } else { __weak __typeof__(self) weakSelf = self; - void (^finished)(UIImage *, NSError *, id downloadIdentifier) = ^(UIImage *responseImage, NSError *error, id downloadIdentifier) { + void (^finished)(id , NSError *, id downloadIdentifier) = ^(id imageContainer, NSError *error, id downloadIdentifier) { __typeof__(self) strongSelf = weakSelf; if (strongSelf == nil) { return; @@ -390,9 +395,13 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; return; } - if (responseImage != NULL) { + if (imageContainer != nil) { strongSelf->_imageLoaded = YES; - strongSelf.image = responseImage; + if ([imageContainer asdk_animatedImageData] && _downloaderImplementsAnimatedImage) { + strongSelf.animatedImage = [_downloader animatedImageWithData:[imageContainer asdk_animatedImageData]]; + } else { + strongSelf.image = [imageContainer asdk_image]; + } } strongSelf->_downloadIdentifier = nil; @@ -402,7 +411,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; { ASDN::MutexLocker l(strongSelf->_lock); - if (responseImage != NULL) { + if (imageContainer != nil) { [strongSelf->_delegate imageNode:strongSelf didLoadImage:strongSelf.image]; } else if (error && _delegateSupportsDidFailWithError) { @@ -415,16 +424,16 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; NSUUID *cacheUUID = [NSUUID UUID]; _cacheUUID = cacheUUID; - void (^cacheCompletion)(UIImage *) = ^(UIImage *image) { + void (^cacheCompletion)(id ) = ^(id imageContainer) { // If the cache UUID changed, that means this request was cancelled. if (![_cacheUUID isEqual:cacheUUID]) { return; } - if (image == NULL && _downloader != nil) { + if ([imageContainer asdk_image] == NULL && _downloader != nil) { [self _downloadImageWithCompletion:finished]; } else { - finished(image, NULL, nil); + finished(imageContainer, NULL, nil); } }; diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 54c34b5813..e686a85f77 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -11,6 +11,7 @@ #import #import +#import #import #import #import @@ -68,6 +69,7 @@ #import #import #import +#import #import #import #import diff --git a/AsyncDisplayKit/Details/ASImageContainerProtocolCategories.h b/AsyncDisplayKit/Details/ASImageContainerProtocolCategories.h new file mode 100644 index 0000000000..dfe9e163c2 --- /dev/null +++ b/AsyncDisplayKit/Details/ASImageContainerProtocolCategories.h @@ -0,0 +1,19 @@ +// +// ASImageContainerProtocolCategories.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 3/18/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +#import "ASImageProtocols.h" + +@interface UIImage (ASImageContainerProtocol) + +@end + +@interface NSData (ASImageContainerProtocol) + +@end diff --git a/AsyncDisplayKit/Details/ASImageContainerProtocolCategories.m b/AsyncDisplayKit/Details/ASImageContainerProtocolCategories.m new file mode 100644 index 0000000000..90b3da6f65 --- /dev/null +++ b/AsyncDisplayKit/Details/ASImageContainerProtocolCategories.m @@ -0,0 +1,37 @@ +// +// ASImageContainerProtocolCategories.m +// AsyncDisplayKit +// +// Created by Garrett Moon on 3/18/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASImageContainerProtocolCategories.h" + +@implementation UIImage (ASImageContainerProtocol) + +- (UIImage *)asdk_image +{ + return self; +} + +- (NSData *)asdk_animatedImageData +{ + return nil; +} + +@end + +@implementation NSData (ASImageContainerProtocol) + +- (UIImage *)asdk_image +{ + return nil; +} + +- (NSData *)asdk_animatedImageData +{ + return self; +} + +@end diff --git a/AsyncDisplayKit/Details/ASImageProtocols.h b/AsyncDisplayKit/Details/ASImageProtocols.h index 25ee762862..3dc5568d06 100644 --- a/AsyncDisplayKit/Details/ASImageProtocols.h +++ b/AsyncDisplayKit/Details/ASImageProtocols.h @@ -11,7 +11,16 @@ NS_ASSUME_NONNULL_BEGIN -typedef void(^ASImageCacherCompletion)(UIImage * _Nullable imageFromCache); +@protocol ASAnimatedImageProtocol; + +@protocol ASImageContainerProtocol + +- (UIImage *)asdk_image; +- (NSData *)asdk_animatedImageData; + +@end + +typedef void(^ASImageCacherCompletion)(id _Nullable imageFromCache); @protocol ASImageCacheProtocol @@ -28,7 +37,7 @@ typedef void(^ASImageCacherCompletion)(UIImage * _Nullable imageFromCache); the calling thread to fetch the image from a fast memory cache. It is OK to return nil from this method and instead support only cachedImageWithURL:callbackQueue:completion: however, synchronous rendering will not be possible. */ -- (nullable UIImage *)synchronouslyFetchedCachedImageWithURL:(NSURL *)URL; +- (nullable id )synchronouslyFetchedCachedImageWithURL:(NSURL *)URL; /** @abstract Attempts to fetch an image with the given URL from the cache. @@ -52,7 +61,7 @@ typedef void(^ASImageCacherCompletion)(UIImage * _Nullable imageFromCache); @end -typedef void(^ASImageDownloaderCompletion)(UIImage * _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier); +typedef void(^ASImageDownloaderCompletion)(id _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier); typedef void(^ASImageDownloaderProgress)(CGFloat progress); typedef void(^ASImageDownloaderProgressImage)(UIImage *progressImage, id _Nullable downloadIdentifier); @@ -76,6 +85,12 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) { @optional +/** + @abstract Return an object that conforms to ASAnimatedImageProtocol + @param animatedImageData Data that represents an animated image. + */ +- (nullable id )animatedImageWithData:(NSData *)animatedImageData; + //You must implement the following method OR the deprecated method at the bottom /** @@ -119,6 +134,27 @@ withDownloadIdentifier:(id)downloadIdentifier; @end +@protocol ASAnimatedImageProtocol + +@property (nonatomic, strong, readwrite) void (^coverImageReadyCallback)(UIImage *coverImage); + +@required + +@property (nonatomic, readonly) UIImage *coverImage; +@property (nonatomic, readonly) BOOL coverImageReady; +@property (nonatomic, readonly) CFTimeInterval totalDuration; +@property (nonatomic, readonly) NSUInteger frameInterval; +@property (nonatomic, readonly) size_t loopCount; +@property (nonatomic, readonly) size_t frameCount; +@property (nonatomic, readonly) BOOL playbackReady; +@property (nonatomic, strong, readwrite) dispatch_block_t playbackReadyCallback; + +- (CGImageRef)imageAtIndex:(NSUInteger)index; +- (CFTimeInterval)durationAtIndex:(NSUInteger)index; +- (void)clearAnimatedImageCache; + +@end + @protocol ASImageDownloaderProtocolDeprecated @optional diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h index 1a7850b2fa..12c6b27376 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h @@ -1,9 +1,9 @@ // // ASPINRemoteImageDownloader.h -// Pods +// AsyncDisplayKit // // Created by Garrett Moon on 2/5/16. -// +// Copyright © 2016 Facebook. All rights reserved. // #import diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m index 13f304f76e..1716006f5f 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m @@ -1,9 +1,9 @@ // // ASPINRemoteImageDownloader.m -// Pods +// AsyncDisplayKit // // Created by Garrett Moon on 2/5/16. -// +// Copyright © 2016 Facebook. All rights reserved. // #ifdef PIN_REMOTE_IMAGE @@ -11,34 +11,104 @@ #import "ASAssert.h" #import "ASThread.h" +#import "ASImageContainerProtocolCategories.h" + +#if __has_include ("PINAnimatedImage.h") +#define PIN_ANIMATED_AVAILABLE 1 +#import "PINAnimatedImage.h" +#import +#else +#define PIN_ANIMATED_AVAILABLE 0 +#endif #import +#import #import +#if PIN_ANIMATED_AVAILABLE +@interface ASPINRemoteImageDownloader () + +@end + +@interface PINAnimatedImage (ASPINRemoteImageDownloader) + +@end + +@implementation PINAnimatedImage (ASPINRemoteImageDownloader) + +- (void)setCoverImageReadyCallback:(void (^)(UIImage * _Nonnull))coverImageReadyCallback +{ + self.infoCompletion = coverImageReadyCallback; +} + +- (void (^)(UIImage * _Nonnull))coverImageReadyCallback +{ + return self.infoCompletion; +} + +- (void)setPlaybackReadyCallback:(dispatch_block_t)playbackReadyCallback +{ + self.fileReady = playbackReadyCallback; +} + +- (dispatch_block_t)playbackReadyCallback +{ + return self.fileReady; +} + +@end +#endif + @implementation ASPINRemoteImageDownloader + (instancetype)sharedDownloader { static ASPINRemoteImageDownloader *sharedDownloader = nil; - static dispatch_once_t once = 0; - dispatch_once(&once, ^{ + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ sharedDownloader = [[ASPINRemoteImageDownloader alloc] init]; }); return sharedDownloader; } +- (PINRemoteImageManager *)sharedPINRemoteImageManager +{ + static PINRemoteImageManager *sharedPINRemoteImageManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if PIN_ANIMATED_AVAILABLE + sharedPINRemoteImageManager = [[PINRemoteImageManager alloc] initWithSessionConfiguration:nil alternativeRepresentationProvider:self]; +#else + sharedPINRemoteImageManager = [[PINRemoteImageManager alloc] initWithSessionConfiguration:nil]; +#endif + }); + return sharedPINRemoteImageManager; +} + #pragma mark ASImageProtocols -- (UIImage *)synchronouslyFetchedCachedImageWithURL:(NSURL *)URL +#if PIN_ANIMATED_AVAILABLE +- (nullable id )animatedImageWithData:(NSData *)animatedImageData { - NSString *key = [[PINRemoteImageManager sharedImageManager] cacheKeyForURL:URL processorKey:nil]; - PINRemoteImageManagerResult *result = [[PINRemoteImageManager sharedImageManager] synchronousImageFromCacheWithCacheKey:key options:PINRemoteImageManagerDownloadOptionsSkipDecode]; + return [[PINAnimatedImage alloc] initWithAnimatedImageData:animatedImageData]; +} +#endif + +- (id )synchronouslyFetchedCachedImageWithURL:(NSURL *)URL; +{ + NSString *key = [[self sharedPINRemoteImageManager] cacheKeyForURL:URL processorKey:nil]; + PINRemoteImageManagerResult *result = [[self sharedPINRemoteImageManager] synchronousImageFromCacheWithCacheKey:key options:PINRemoteImageManagerDownloadOptionsSkipDecode]; +#if PIN_ANIMATED_AVAILABLE + if (result.alternativeRepresentation) { + return result.alternativeRepresentation; + } +#endif return result.image; } -- (void)fetchCachedImageWithURL:(NSURL *)URL - callbackQueue:(dispatch_queue_t)callbackQueue - completion:(void (^)(CGImageRef imageFromCache))completion +- (void)cachedImageWithURL:(NSURL *)URL + callbackQueue:(dispatch_queue_t)callbackQueue + completion:(ASImageCacherCompletion)completion { // We do not check the cache here and instead check it in downloadImageWithURL to avoid checking the cache twice. // If we're targeting the main queue and we're on the main thread, complete immediately. @@ -53,23 +123,39 @@ - (void)clearFetchedImageFromCacheWithURL:(NSURL *)URL { - PINRemoteImageManager *manager = [PINRemoteImageManager sharedImageManager]; + PINRemoteImageManager *manager = [self sharedPINRemoteImageManager]; NSString *key = [manager cacheKeyForURL:URL processorKey:nil]; [[[manager cache] memoryCache] removeObjectForKey:key]; } - (nullable id)downloadImageWithURL:(NSURL *)URL callbackQueue:(dispatch_queue_t)callbackQueue - downloadProgress:(void (^)(CGFloat progress))downloadProgressBlock - completion:(void (^)(UIImage *image, NSError * error, id downloadIdentifier))completion + downloadProgress:(ASImageDownloaderProgress)downloadProgress + completion:(ASImageDownloaderCompletion)completion; { - return [[PINRemoteImageManager sharedImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode completion:^(PINRemoteImageManagerResult *result) { + return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode completion:^(PINRemoteImageManagerResult *result) { /// If we're targeting the main queue and we're on the main thread, complete immediately. if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) { - completion(result.image, result.error, result.UUID); +#if PIN_ANIMATED_AVAILABLE + if (result.alternativeRepresentation) { + completion(result.alternativeRepresentation, result.error, result.UUID); + } else { + completion(result.image, result.error, result.UUID); + } +#else + completion(result.image, result.error, result.UUID); +#endif } else { dispatch_async(callbackQueue, ^{ +#if PIN_ANIMATED_AVAILABLE + if (result.alternativeRepresentation) { + completion(result.alternativeRepresentation, result.error, result.UUID); + } else { + completion(result.image, result.error, result.UUID); + } +#else completion(result.image, result.error, result.UUID); +#endif }); } }]; @@ -78,7 +164,7 @@ - (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier { ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID"); - [[PINRemoteImageManager sharedImageManager] cancelTaskWithUUID:downloadIdentifier]; + [[self sharedPINRemoteImageManager] cancelTaskWithUUID:downloadIdentifier]; } - (void)setProgressImageBlock:(ASImageDownloaderProgressImage)progressBlock callbackQueue:(dispatch_queue_t)callbackQueue withDownloadIdentifier:(id)downloadIdentifier @@ -86,13 +172,13 @@ ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID"); if (progressBlock) { - [[PINRemoteImageManager sharedImageManager] setProgressImageCallback:^(PINRemoteImageManagerResult * _Nonnull result) { + [[self sharedPINRemoteImageManager] setProgressImageCallback:^(PINRemoteImageManagerResult * _Nonnull result) { dispatch_async(callbackQueue, ^{ progressBlock(result.image, result.UUID); }); } ofTaskWithUUID:downloadIdentifier]; } else { - [[PINRemoteImageManager sharedImageManager] setProgressImageCallback:nil ofTaskWithUUID:downloadIdentifier]; + [[self sharedPINRemoteImageManager] setProgressImageCallback:nil ofTaskWithUUID:downloadIdentifier]; } } @@ -114,7 +200,19 @@ pi_priority = PINRemoteImageManagerPriorityVeryHigh; break; } - [[PINRemoteImageManager sharedImageManager] setPriority:pi_priority ofTaskWithUUID:downloadIdentifier]; + [[self sharedPINRemoteImageManager] setPriority:pi_priority ofTaskWithUUID:downloadIdentifier]; +} + +#pragma mark - PINRemoteImageManagerAlternateRepresentationProvider + +- (id)alternateRepresentationWithData:(NSData *)data options:(PINRemoteImageManagerDownloadOptions)options +{ +#if PIN_ANIMATED_AVAILABLE + if ([data pin_isGIF]) { + return data; + } +#endif + return nil; } @end diff --git a/AsyncDisplayKit/Details/ASWeakProxy.h b/AsyncDisplayKit/Details/ASWeakProxy.h new file mode 100644 index 0000000000..d0598bb647 --- /dev/null +++ b/AsyncDisplayKit/Details/ASWeakProxy.h @@ -0,0 +1,17 @@ +// +// ASWeakProxy.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 4/12/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +@interface ASWeakProxy : NSObject + +@property (nonatomic, weak, readonly) id target; + ++ (instancetype)weakProxyWithTarget:(id)target; + +@end diff --git a/AsyncDisplayKit/Details/ASWeakProxy.m b/AsyncDisplayKit/Details/ASWeakProxy.m new file mode 100644 index 0000000000..e30f4e7e4f --- /dev/null +++ b/AsyncDisplayKit/Details/ASWeakProxy.m @@ -0,0 +1,31 @@ +// +// ASWeakProxy.m +// AsyncDisplayKit +// +// Created by Garrett Moon on 4/12/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASWeakProxy.h" + +@implementation ASWeakProxy + +- (instancetype)initWithTarget:(id)target +{ + if (self = [super init]) { + _target = target; + } + return self; +} + ++ (instancetype)weakProxyWithTarget:(id)target +{ + return [[ASWeakProxy alloc] initWithTarget:target]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _target; +} + +@end diff --git a/AsyncDisplayKit/Private/ASImageNode+AnimatedImagePrivate.h b/AsyncDisplayKit/Private/ASImageNode+AnimatedImagePrivate.h new file mode 100644 index 0000000000..2814ef9ddc --- /dev/null +++ b/AsyncDisplayKit/Private/ASImageNode+AnimatedImagePrivate.h @@ -0,0 +1,27 @@ +// +// ASImageNode+AnimatedImagePrivate.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 3/30/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASThread.h" + +@interface ASImageNode () +{ + ASDN::RecursiveMutex _animatedImageLock; + ASDN::RecursiveMutex _animatedImagePausedLock; + ASDN::Mutex _displayLinkLock; + id _animatedImage; + BOOL _animatedImagePaused; + CADisplayLink *_displayLink; + + //accessed on main thread only + CFTimeInterval _playHead; + NSUInteger _playedLoops; +} + +@property (atomic, assign) CFTimeInterval lastDisplayLinkFire; + +@end diff --git a/AsyncDisplayKitTests/ASMultiplexImageNodeTests.m b/AsyncDisplayKitTests/ASMultiplexImageNodeTests.m index 5a1d967787..7fef1de042 100644 --- a/AsyncDisplayKitTests/ASMultiplexImageNodeTests.m +++ b/AsyncDisplayKitTests/ASMultiplexImageNodeTests.m @@ -10,6 +10,7 @@ #import #import +#import #import diff --git a/examples/ASAnimatedImage/ASAnimatedImage/AppDelegate.h b/examples/ASAnimatedImage/ASAnimatedImage/AppDelegate.h new file mode 100644 index 0000000000..b3ea365221 --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// ASAnimatedImage +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook, Inc. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/examples/ASAnimatedImage/ASAnimatedImage/AppDelegate.m b/examples/ASAnimatedImage/ASAnimatedImage/AppDelegate.m new file mode 100644 index 0000000000..b4a601de56 --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/AppDelegate.m @@ -0,0 +1,45 @@ +// +// AppDelegate.m +// ASAnimatedImage +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook, Inc. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/examples/ASAnimatedImage/ASAnimatedImage/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/ASAnimatedImage/ASAnimatedImage/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..36d2c80d88 --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/ASAnimatedImage/ASAnimatedImage/Base.lproj/LaunchScreen.storyboard b/examples/ASAnimatedImage/ASAnimatedImage/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..2e721e1833 --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/ASAnimatedImage/ASAnimatedImage/Base.lproj/Main.storyboard b/examples/ASAnimatedImage/ASAnimatedImage/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..f56d2f3bb5 --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/ASAnimatedImage/ASAnimatedImage/Info.plist b/examples/ASAnimatedImage/ASAnimatedImage/Info.plist new file mode 100644 index 0000000000..40c6215d90 --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/ASAnimatedImage/ASAnimatedImage/ViewController.h b/examples/ASAnimatedImage/ASAnimatedImage/ViewController.h new file mode 100644 index 0000000000..5fce20369d --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// ASAnimatedImage +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook, Inc. All rights reserved. +// + +#import + +@interface ViewController : UIViewController + + +@end + diff --git a/examples/ASAnimatedImage/ASAnimatedImage/ViewController.m b/examples/ASAnimatedImage/ASAnimatedImage/ViewController.m new file mode 100644 index 0000000000..9087dfdd5d --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/ViewController.m @@ -0,0 +1,37 @@ +// +// ViewController.m +// ASAnimatedImage +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook, Inc. All rights reserved. +// + +#import "ViewController.h" + +#import + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + + ASNetworkImageNode *imageNode = [[ASNetworkImageNode alloc] init]; + imageNode.URL = [NSURL URLWithString:@"https://s-media-cache-ak0.pinimg.com/originals/07/44/38/074438e7c75034df2dcf37ba1057803e.gif"]; + imageNode.frame = self.view.bounds; + imageNode.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + imageNode.contentMode = UIViewContentModeScaleAspectFit; + + [self.view addSubnode:imageNode]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/examples/ASAnimatedImage/ASAnimatedImage/main.m b/examples/ASAnimatedImage/ASAnimatedImage/main.m new file mode 100644 index 0000000000..dd6cdbdb8a --- /dev/null +++ b/examples/ASAnimatedImage/ASAnimatedImage/main.m @@ -0,0 +1,16 @@ +// +// main.m +// ASAnimatedImage +// +// Created by Garrett Moon on 3/22/16. +// Copyright © 2016 Facebook, Inc. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/examples/ASAnimatedImage/Podfile b/examples/ASAnimatedImage/Podfile new file mode 100644 index 0000000000..5e6d5cc415 --- /dev/null +++ b/examples/ASAnimatedImage/Podfile @@ -0,0 +1,4 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' +pod 'AsyncDisplayKit', :path => '../..' +pod 'PINRemoteImage', :git => 'https://github.com/pinterest/PINRemoteImage.git', :branch => 'addPINAnimatedImage' diff --git a/examples/ASAnimatedImage/Sample.xcodeproj/project.pbxproj b/examples/ASAnimatedImage/Sample.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..eaaaed2bad --- /dev/null +++ b/examples/ASAnimatedImage/Sample.xcodeproj/project.pbxproj @@ -0,0 +1,385 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 683ADBA31CA19883005863A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 683ADBA21CA19883005863A4 /* main.m */; }; + 683ADBA61CA19883005863A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 683ADBA51CA19883005863A4 /* AppDelegate.m */; }; + 683ADBA91CA19883005863A4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 683ADBA81CA19883005863A4 /* ViewController.m */; }; + 683ADBAC1CA19883005863A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 683ADBAA1CA19883005863A4 /* Main.storyboard */; }; + 683ADBAE1CA19883005863A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 683ADBAD1CA19883005863A4 /* Assets.xcassets */; }; + 683ADBB11CA19883005863A4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 683ADBAF1CA19883005863A4 /* LaunchScreen.storyboard */; }; + EE964E5E7CD506D45C6DCC49 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A6F2399FA1A86586D9BDAE05 /* libPods.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 683ADB9E1CA19883005863A4 /* ASAnimatedImage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ASAnimatedImage.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 683ADBA21CA19883005863A4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 683ADBA41CA19883005863A4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 683ADBA51CA19883005863A4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 683ADBA71CA19883005863A4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 683ADBA81CA19883005863A4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 683ADBAB1CA19883005863A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 683ADBAD1CA19883005863A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 683ADBB01CA19883005863A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 683ADBB21CA19883005863A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A6F2399FA1A86586D9BDAE05 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + BBB395EF2813E7DB5CB49459 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + BBBE85D30A6D31AD7021A9AF /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 683ADB9B1CA19883005863A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE964E5E7CD506D45C6DCC49 /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 683ADB951CA19883005863A4 = { + isa = PBXGroup; + children = ( + 683ADBA01CA19883005863A4 /* ASAnimatedImage */, + 683ADB9F1CA19883005863A4 /* Products */, + 71A772B0DB9B7760CE330DD9 /* Pods */, + 8C6AC07DE55B51935C632F56 /* Frameworks */, + ); + sourceTree = ""; + }; + 683ADB9F1CA19883005863A4 /* Products */ = { + isa = PBXGroup; + children = ( + 683ADB9E1CA19883005863A4 /* ASAnimatedImage.app */, + ); + name = Products; + sourceTree = ""; + }; + 683ADBA01CA19883005863A4 /* ASAnimatedImage */ = { + isa = PBXGroup; + children = ( + 683ADBA41CA19883005863A4 /* AppDelegate.h */, + 683ADBA51CA19883005863A4 /* AppDelegate.m */, + 683ADBA71CA19883005863A4 /* ViewController.h */, + 683ADBA81CA19883005863A4 /* ViewController.m */, + 683ADBAA1CA19883005863A4 /* Main.storyboard */, + 683ADBAD1CA19883005863A4 /* Assets.xcassets */, + 683ADBAF1CA19883005863A4 /* LaunchScreen.storyboard */, + 683ADBB21CA19883005863A4 /* Info.plist */, + 683ADBA11CA19883005863A4 /* Supporting Files */, + ); + path = ASAnimatedImage; + sourceTree = ""; + }; + 683ADBA11CA19883005863A4 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 683ADBA21CA19883005863A4 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 71A772B0DB9B7760CE330DD9 /* Pods */ = { + isa = PBXGroup; + children = ( + BBBE85D30A6D31AD7021A9AF /* Pods.debug.xcconfig */, + BBB395EF2813E7DB5CB49459 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 8C6AC07DE55B51935C632F56 /* Frameworks */ = { + isa = PBXGroup; + children = ( + A6F2399FA1A86586D9BDAE05 /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 683ADB9D1CA19883005863A4 /* ASAnimatedImage */ = { + isa = PBXNativeTarget; + buildConfigurationList = 683ADBB51CA19883005863A4 /* Build configuration list for PBXNativeTarget "ASAnimatedImage" */; + buildPhases = ( + 694B306B43ED1C3916B0D909 /* Check Pods Manifest.lock */, + 683ADB9A1CA19883005863A4 /* Sources */, + 683ADB9B1CA19883005863A4 /* Frameworks */, + 683ADB9C1CA19883005863A4 /* Resources */, + 26A96BEEF893B1FA39F144CF /* Embed Pods Frameworks */, + 2ADE0E7B5309A9CD043DDB3E /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ASAnimatedImage; + productName = ASAnimatedImage; + productReference = 683ADB9E1CA19883005863A4 /* ASAnimatedImage.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 683ADB961CA19883005863A4 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Facebook, Inc."; + TargetAttributes = { + 683ADB9D1CA19883005863A4 = { + CreatedOnToolsVersion = 7.2; + }; + }; + }; + buildConfigurationList = 683ADB991CA19883005863A4 /* Build configuration list for PBXProject "ASAnimatedImage" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 683ADB951CA19883005863A4; + productRefGroup = 683ADB9F1CA19883005863A4 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 683ADB9D1CA19883005863A4 /* ASAnimatedImage */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 683ADB9C1CA19883005863A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 683ADBB11CA19883005863A4 /* LaunchScreen.storyboard in Resources */, + 683ADBAE1CA19883005863A4 /* Assets.xcassets in Resources */, + 683ADBAC1CA19883005863A4 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 26A96BEEF893B1FA39F144CF /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 2ADE0E7B5309A9CD043DDB3E /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 694B306B43ED1C3916B0D909 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 683ADB9A1CA19883005863A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 683ADBA91CA19883005863A4 /* ViewController.m in Sources */, + 683ADBA61CA19883005863A4 /* AppDelegate.m in Sources */, + 683ADBA31CA19883005863A4 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 683ADBAA1CA19883005863A4 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 683ADBAB1CA19883005863A4 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 683ADBAF1CA19883005863A4 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 683ADBB01CA19883005863A4 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 683ADBB31CA19883005863A4 /* 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; + DEBUG_INFORMATION_FORMAT = dwarf; + 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_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 = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 683ADBB41CA19883005863A4 /* 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; + 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 = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 683ADBB61CA19883005863A4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BBBE85D30A6D31AD7021A9AF /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = ASAnimatedImage/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = facebook.ASAnimatedImage; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 683ADBB71CA19883005863A4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BBB395EF2813E7DB5CB49459 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = ASAnimatedImage/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = facebook.ASAnimatedImage; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 683ADB991CA19883005863A4 /* Build configuration list for PBXProject "ASAnimatedImage" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 683ADBB31CA19883005863A4 /* Debug */, + 683ADBB41CA19883005863A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 683ADBB51CA19883005863A4 /* Build configuration list for PBXNativeTarget "ASAnimatedImage" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 683ADBB61CA19883005863A4 /* Debug */, + 683ADBB71CA19883005863A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 683ADB961CA19883005863A4 /* Project object */; +} diff --git a/examples/ASAnimatedImage/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/ASAnimatedImage/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..dd7b72cdff --- /dev/null +++ b/examples/ASAnimatedImage/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/ASAnimatedImage/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/examples/ASAnimatedImage/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme new file mode 100644 index 0000000000..16cb2bd07c --- /dev/null +++ b/examples/ASAnimatedImage/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/ASAnimatedImage/Sample.xcworkspace/contents.xcworkspacedata b/examples/ASAnimatedImage/Sample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..7b5a2f3050 --- /dev/null +++ b/examples/ASAnimatedImage/Sample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + +