diff --git a/.travis.yml b/.travis.yml index fd3259ebdf..69217e9a71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: objective-c -osx_image: xcode7.2 +osx_image: xcode7.3 before_install: - brew update - - brew reinstall xctool + - brew reinstall --HEAD xctool + - brew reinstall carthage - gem install cocoapods -v 0.38.2 - gem install slather - xcrun simctl list diff --git a/AsyncDisplayKit.podspec b/AsyncDisplayKit.podspec index 1516962121..2a132397d0 100644 --- a/AsyncDisplayKit.podspec +++ b/AsyncDisplayKit.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |spec| spec.name = 'AsyncDisplayKit' - spec.version = '1.9.7' + spec.version = '1.9.8' spec.license = { :type => 'BSD' } spec.homepage = 'http://asyncdisplaykit.org' spec.authors = { 'Scott Goodson' => 'scottgoodson@gmail.com', 'Ryan Nystrom' => 'rnystrom@fb.com' } spec.summary = 'Smooth asynchronous user interfaces for iOS apps.' - spec.source = { :git => 'https://github.com/facebook/AsyncDisplayKit.git', :tag => '1.9.7' } + spec.source = { :git => 'https://github.com/facebook/AsyncDisplayKit.git', :tag => '1.9.7.1' } spec.documentation_url = 'http://asyncdisplaykit.org/appledoc/' @@ -14,7 +14,8 @@ Pod::Spec.new do |spec| 'AsyncDisplayKit/Details/**/*.h', 'AsyncDisplayKit/Layout/*.h', 'Base/*.h', - 'AsyncDisplayKit/TextKit/ASTextNodeTypes.h' + 'AsyncDisplayKit/TextKit/ASTextNodeTypes.h', + 'AsyncDisplayKit/TextKit/ASTextKitComponents.h' ] spec.source_files = [ @@ -51,7 +52,7 @@ Pod::Spec.new do |spec| spec.subspec 'PINRemoteImage' do |pin| pin.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) PIN_REMOTE_IMAGE=1' } - pin.dependency 'PINRemoteImage/iOS', '>= 2.1' + pin.dependency 'PINRemoteImage/iOS', '>= 2.1.2' pin.dependency 'AsyncDisplayKit/ASDealloc2MainObject' end diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 91db74aa94..1d77edc23e 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -136,7 +136,7 @@ 254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 254C6B531BF8FF2A003EC431 /* ASTextKitTests.mm */; }; 254C6B731BF94DF4003EC431 /* ASTextKitCoreTextAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */; }; 254C6B741BF94DF4003EC431 /* ASTextNodeWordKerner.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754B91BEE458E00737CA5 /* ASTextNodeWordKerner.h */; }; - 254C6B751BF94DF4003EC431 /* ASTextKitHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BA1BEE458E00737CA5 /* ASTextKitHelpers.h */; }; + 254C6B751BF94DF4003EC431 /* ASTextKitComponents.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BA1BEE458E00737CA5 /* ASTextKitComponents.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254C6B761BF94DF4003EC431 /* ASTextNodeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254C6B771BF94DF4003EC431 /* ASTextKitAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754951BEE44CD00737CA5 /* ASTextKitAttributes.h */; }; 254C6B781BF94DF4003EC431 /* ASTextKitContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754961BEE44CD00737CA5 /* ASTextKitContext.h */; }; @@ -148,7 +148,7 @@ 254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A11BEE44CD00737CA5 /* ASTextKitTailTruncater.h */; }; 254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A31BEE44CD00737CA5 /* ASTextKitTruncating.h */; }; 254C6B801BF94DF4003EC431 /* ASEqualityHashHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A41BEE44CD00737CA5 /* ASEqualityHashHelpers.h */; }; - 254C6B821BF94F8A003EC431 /* ASTextKitHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitHelpers.mm */; }; + 254C6B821BF94F8A003EC431 /* ASTextKitComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitComponents.m */; }; 254C6B831BF94F8A003EC431 /* ASTextKitCoreTextAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */; }; 254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */; }; 254C6B851BF94F8A003EC431 /* ASTextKitAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754941BEE44CD00737CA5 /* ASTextKitAttributes.mm */; }; @@ -179,10 +179,10 @@ 257754B41BEE44CD00737CA5 /* ASTextKitTailTruncater.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754A21BEE44CD00737CA5 /* ASTextKitTailTruncater.mm */; }; 257754B51BEE44CD00737CA5 /* ASTextKitTruncating.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A31BEE44CD00737CA5 /* ASTextKitTruncating.h */; settings = {ATTRIBUTES = (Public, ); }; }; 257754B61BEE44CD00737CA5 /* ASEqualityHashHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A41BEE44CD00737CA5 /* ASEqualityHashHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 257754BE1BEE458E00737CA5 /* ASTextKitHelpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitHelpers.mm */; }; + 257754BE1BEE458E00737CA5 /* ASTextKitComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitComponents.m */; }; 257754BF1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */; }; 257754C01BEE458E00737CA5 /* ASTextNodeWordKerner.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754B91BEE458E00737CA5 /* ASTextNodeWordKerner.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 257754C11BEE458E00737CA5 /* ASTextKitHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BA1BEE458E00737CA5 /* ASTextKitHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 257754C11BEE458E00737CA5 /* ASTextKitComponents.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BA1BEE458E00737CA5 /* ASTextKitComponents.h */; settings = {ATTRIBUTES = (Public, ); }; }; 257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 257754C31BEE458E00737CA5 /* ASTextNodeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 257754C41BEE458E00737CA5 /* ASTextNodeWordKerner.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */; }; @@ -258,13 +258,29 @@ 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; + 698548631CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 698548641CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 698548651CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; + 698548661CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; + 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 698C8B621CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69E1006D1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */; }; + 69E1006E1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */; }; + 69E1006F1CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */; }; + 69E100701CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */; }; 69F10C861C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7630FFA81C9E267E007A7C0E /* ASVideoNode.h in Headers */ = {isa = PBXBuildFile; fileRef = AEEC47DF1C20C2DD00EC1693 /* ASVideoNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 764D83D51C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */; settings = {ATTRIBUTES = (Public, ); }; }; 764D83D61C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */; }; 767E7F8D1C9019130066C000 /* AsyncDisplayKit+Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */; settings = {ATTRIBUTES = (Public, ); }; }; 767E7F8E1C90191D0066C000 /* AsyncDisplayKit+Debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */; }; + 7A06A73A1C35F08800FE8DAA /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; }; + 7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; }; + 7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */; }; 81EE384F1C8E94F000456208 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; }; 92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -282,14 +298,6 @@ 9C55866A1BD549CB00B50E3A /* ASAsciiArtBoxCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */; }; 9C55866B1BD54A1900B50E3A /* ASAsciiArtBoxCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */; }; 9C55866C1BD54A3000B50E3A /* ASAsciiArtBoxCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C5FA3511B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C5FA3521B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C5FA3531B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */; }; - 9C5FA3541B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */; }; - 9C5FA35F1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */; }; - 9C5FA3601B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */; }; - 9C65A72A1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */; }; - 9C65A72B1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */; }; 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; @@ -364,15 +372,15 @@ ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */; }; AEB7B01A1C5962EA00662EF4 /* ASDefaultPlayButton.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */; }; AEB7B01B1C5962EA00662EF4 /* ASDefaultPlayButton.m in Sources */ = {isa = PBXBuildFile; fileRef = AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */; }; - AEEC47E11C20C2DD00EC1693 /* ASVideoNode.h in Headers */ = {isa = PBXBuildFile; fileRef = AEEC47DF1C20C2DD00EC1693 /* ASVideoNode.h */; }; + AEEC47E11C20C2DD00EC1693 /* ASVideoNode.h in Headers */ = {isa = PBXBuildFile; fileRef = AEEC47DF1C20C2DD00EC1693 /* ASVideoNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; AEEC47E21C20C2DD00EC1693 /* ASVideoNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E01C20C2DD00EC1693 /* ASVideoNode.mm */; }; AEEC47E41C21D3D200EC1693 /* ASVideoNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E31C21D3D200EC1693 /* ASVideoNodeTests.m */; }; B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; - B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; - B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; - B13CA1001C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; }; - B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; }; + B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B13CA1001C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; B30BF6521C5964B0004FCD53 /* ASLayoutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */; }; B30BF6531C5964B0004FCD53 /* ASLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B30BF6511C5964B0004FCD53 /* ASLayoutManager.m */; }; B30BF6541C59D889004FCD53 /* ASLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B30BF6511C5964B0004FCD53 /* ASLayoutManager.m */; }; @@ -518,6 +526,8 @@ DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; }; E52405B31C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */; }; E52405B51C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */; }; + E55D86321CA8A14000A0C26F /* ASLayoutable.mm in Sources */ = {isa = PBXBuildFile; fileRef = E55D86311CA8A14000A0C26F /* ASLayoutable.mm */; }; + E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */ = {isa = PBXBuildFile; fileRef = E55D86311CA8A14000A0C26F /* ASLayoutable.mm */; }; E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; }; E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.m in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */; }; @@ -704,10 +714,10 @@ 257754A21BEE44CD00737CA5 /* ASTextKitTailTruncater.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitTailTruncater.mm; path = TextKit/ASTextKitTailTruncater.mm; sourceTree = ""; }; 257754A31BEE44CD00737CA5 /* ASTextKitTruncating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitTruncating.h; path = TextKit/ASTextKitTruncating.h; sourceTree = ""; }; 257754A41BEE44CD00737CA5 /* ASEqualityHashHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASEqualityHashHelpers.h; path = TextKit/ASEqualityHashHelpers.h; sourceTree = ""; }; - 257754B71BEE458D00737CA5 /* ASTextKitHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitHelpers.mm; path = TextKit/ASTextKitHelpers.mm; sourceTree = ""; }; + 257754B71BEE458D00737CA5 /* ASTextKitComponents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextKitComponents.m; path = TextKit/ASTextKitComponents.m; sourceTree = ""; }; 257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextKitCoreTextAdditions.m; path = TextKit/ASTextKitCoreTextAdditions.m; sourceTree = ""; }; 257754B91BEE458E00737CA5 /* ASTextNodeWordKerner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeWordKerner.h; path = TextKit/ASTextNodeWordKerner.h; sourceTree = ""; }; - 257754BA1BEE458E00737CA5 /* ASTextKitHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitHelpers.h; path = TextKit/ASTextKitHelpers.h; sourceTree = ""; }; + 257754BA1BEE458E00737CA5 /* ASTextKitComponents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitComponents.h; path = TextKit/ASTextKitComponents.h; sourceTree = ""; }; 257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitCoreTextAdditions.h; path = TextKit/ASTextKitCoreTextAdditions.h; sourceTree = ""; }; 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeTypes.h; path = TextKit/ASTextNodeTypes.h; sourceTree = ""; }; 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextNodeWordKerner.m; path = TextKit/ASTextNodeWordKerner.m; sourceTree = ""; }; @@ -732,10 +742,18 @@ 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+Beta.h"; 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 = ""; }; + 698548621CA9E025008A345F /* ASEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASEnvironment.m; sourceTree = ""; }; + 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutableExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutableExtensibility.h; sourceTree = ""; }; + 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironmentInternal.h; sourceTree = ""; }; + 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASEnvironmentInternal.mm; sourceTree = ""; }; 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASRangeControllerUpdateRangeProtocol+Beta.h"; sourceTree = ""; }; 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = ""; }; 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AsyncDisplayKit+Debug.h"; sourceTree = ""; }; 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AsyncDisplayKit+Debug.m"; sourceTree = ""; }; + 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRelativeLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm; sourceTree = ""; }; + 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRelativeLayoutSpec.h; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h; sourceTree = ""; }; + 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRelativeLayoutSpecSnapshotTests.mm; sourceTree = ""; }; 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = ""; }; 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = ""; }; 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = ""; }; @@ -744,10 +762,6 @@ 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutable.h; path = AsyncDisplayKit/Layout/ASStackLayoutable.h; sourceTree = ""; }; 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASAsciiArtBoxCreator.h; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.h; sourceTree = ""; }; 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASAsciiArtBoxCreator.m; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.m; sourceTree = ""; }; - 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutOptions.h; path = AsyncDisplayKit/Layout/ASLayoutOptions.h; sourceTree = ""; }; - 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutOptions.mm; path = AsyncDisplayKit/Layout/ASLayoutOptions.mm; sourceTree = ""; }; - 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutOptionsPrivate.mm; path = AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm; sourceTree = ""; }; - 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutOptionsPrivate.h; sourceTree = ""; }; 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutable.h; path = AsyncDisplayKit/Layout/ASStaticLayoutable.h; sourceTree = ""; }; 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackBaselinePositionedLayout.h; sourceTree = ""; }; 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackBaselinePositionedLayout.mm; sourceTree = ""; }; @@ -791,7 +805,7 @@ ACF6ED161B17843500DA7C62 /* ASStackLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutSpec.h; path = AsyncDisplayKit/Layout/ASStackLayoutSpec.h; sourceTree = ""; }; ACF6ED171B17843500DA7C62 /* ASStackLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASStackLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASStackLayoutSpec.mm; sourceTree = ""; }; ACF6ED181B17843500DA7C62 /* ASStaticLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutSpec.h; path = AsyncDisplayKit/Layout/ASStaticLayoutSpec.h; sourceTree = ""; }; - ACF6ED191B17843500DA7C62 /* ASStaticLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASStaticLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED191B17843500DA7C62 /* ASStaticLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASStaticLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm; sourceTree = ""; }; ACF6ED431B17847A00DA7C62 /* ASInternalHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASInternalHelpers.h; sourceTree = ""; }; ACF6ED441B17847A00DA7C62 /* ASInternalHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASInternalHelpers.mm; sourceTree = ""; }; ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutSpecUtilities.h; sourceTree = ""; }; @@ -799,7 +813,7 @@ ACF6ED471B17847A00DA7C62 /* ASStackPositionedLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackPositionedLayout.h; sourceTree = ""; }; ACF6ED481B17847A00DA7C62 /* ASStackPositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackPositionedLayout.mm; sourceTree = ""; }; ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackUnpositionedLayout.h; sourceTree = ""; }; - ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASStackUnpositionedLayout.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASStackUnpositionedLayout.mm; sourceTree = ""; }; ACF6ED531B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCenterLayoutSpecSnapshotTests.mm; sourceTree = ""; }; ACF6ED541B178DC700DA7C62 /* ASDimensionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDimensionTests.mm; sourceTree = ""; }; ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASInsetLayoutSpecSnapshotTests.mm; sourceTree = ""; }; @@ -851,6 +865,7 @@ DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = ""; }; E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayoutContext.mm; sourceTree = ""; }; E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeLayoutContext.h; sourceTree = ""; }; + E55D86311CA8A14000A0C26F /* ASLayoutable.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutable.mm; path = AsyncDisplayKit/Layout/ASLayoutable.mm; sourceTree = ""; }; E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexedNodeContext.h; sourceTree = ""; }; E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIndexedNodeContext.m; sourceTree = ""; }; EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1056,6 +1071,7 @@ 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */, 056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.m */, ACF6ED531B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm */, + 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */, ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */, ACF6ED591B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm */, ACF6ED5A1B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm */, @@ -1103,14 +1119,6 @@ 058D09E1195D050800B7D73C /* Details */ = { isa = PBXGroup; children = ( - 25B171EA1C12242700508A7A /* Data Controller */, - 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */, - 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */, - CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */, - CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */, - 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */, - 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */, - 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */, 058D09E2195D050800B7D73C /* _ASDisplayLayer.h */, 058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */, 058D09E4195D050800B7D73C /* _ASDisplayView.h */, @@ -1121,31 +1129,41 @@ 054963481A1EA066000F8E56 /* ASBasicImageDownloader.mm */, 299DA1A71A828D2900162D41 /* ASBatchContext.h */, 299DA1A81A828D2900162D41 /* ASBatchContext.mm */, + 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */, + 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */, 205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */, 205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */, + 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */, 05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */, 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */, + 698548611CA9E025008A345F /* ASEnvironment.h */, + 698548621CA9E025008A345F /* ASEnvironment.m */, 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */, 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */, 058D09E6195D050800B7D73C /* ASHighlightOverlayLayer.h */, 058D09E7195D050800B7D73C /* ASHighlightOverlayLayer.mm */, + 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */, 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */, - 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, 4640521D1A3F83C40061C0BA /* ASLayoutController.h */, 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */, 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */, 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */, 058D09E8195D050800B7D73C /* ASMutableAttributedStringBuilder.h */, 058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */, + CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */, + CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */, 055F1A3619ABD413004DAFF1 /* ASRangeController.h */, 055F1A3719ABD413004DAFF1 /* ASRangeController.mm */, 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */, + 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */, + 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */, 296A0A311A951715005ACEAA /* ASScrollDirection.h */, 205F0E111B371BD7007741D0 /* ASScrollDirection.m */, 058D0A12195D050800B7D73C /* ASThread.h */, 205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */, 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */, + 25B171EA1C12242700508A7A /* Data Controller */, 058D09F5195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.h */, 058D09F6195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.m */, 058D09F7195D050800B7D73C /* Transactions */, @@ -1173,50 +1191,51 @@ 058D0A01195D050800B7D73C /* Private */ = { isa = PBXGroup; children = ( - DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */, - DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */, - CC3B20811C3F76D600798563 /* ASPendingStateController.h */, - CC3B20821C3F76D600798563 /* ASPendingStateController.mm */, - CC3B20871C3F7A5400798563 /* ASWeakSet.h */, - CC3B20881C3F7A5400798563 /* ASWeakSet.m */, - AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */, - AC026B6E1BD57DBF00BBC17E /* _ASHierarchyChangeSet.m */, - 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */, - 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */, - 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */, - 2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */, 058D0A02195D050800B7D73C /* _AS-objc-internal.h */, 058D0A03195D050800B7D73C /* _ASCoreAnimationExtras.h */, 058D0A04195D050800B7D73C /* _ASCoreAnimationExtras.mm */, + AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */, + AC026B6E1BD57DBF00BBC17E /* _ASHierarchyChangeSet.m */, 058D0A05195D050800B7D73C /* _ASPendingState.h */, 058D0A06195D050800B7D73C /* _ASPendingState.mm */, 058D0A07195D050800B7D73C /* _ASScopeTimer.h */, - 058D0A08195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm */, + DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */, + DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */, + 2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */, 044285051BAA63FE00D16268 /* ASBatchFetching.h */, 044285061BAA63FE00D16268 /* ASBatchFetching.m */, + AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */, + AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */, + 058D0A08195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm */, 058D0A09195D050800B7D73C /* ASDisplayNode+DebugTiming.h */, 058D0A0A195D050800B7D73C /* ASDisplayNode+DebugTiming.mm */, - 058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */, DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */, + 058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */, + 058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */, E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */, E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */, - 058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */, + 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */, + 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */, 058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */, 058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */, - 058D0A10195D050800B7D73C /* ASSentinel.h */, - 058D0A11195D050800B7D73C /* ASSentinel.m */, ACF6ED431B17847A00DA7C62 /* ASInternalHelpers.h */, ACF6ED441B17847A00DA7C62 /* ASInternalHelpers.mm */, ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */, + 0442850B1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h */, + 0442850C1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm */, + CC3B20811C3F76D600798563 /* ASPendingStateController.h */, + CC3B20821C3F76D600798563 /* ASPendingStateController.mm */, + 058D0A10195D050800B7D73C /* ASSentinel.h */, + 058D0A11195D050800B7D73C /* ASSentinel.m */, + 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */, + 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */, ACF6ED461B17847A00DA7C62 /* ASStackLayoutSpecUtilities.h */, ACF6ED471B17847A00DA7C62 /* ASStackPositionedLayout.h */, ACF6ED481B17847A00DA7C62 /* ASStackPositionedLayout.mm */, ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */, ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */, - 0442850B1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h */, - 0442850C1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm */, - AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */, - AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */, + CC3B20871C3F7A5400798563 /* ASWeakSet.h */, + CC3B20881C3F7A5400798563 /* ASWeakSet.m */, DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */, DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */, ); @@ -1241,11 +1260,11 @@ children = ( B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */, B30BF6511C5964B0004FCD53 /* ASLayoutManager.m */, - 257754B71BEE458D00737CA5 /* ASTextKitHelpers.mm */, + 257754BA1BEE458E00737CA5 /* ASTextKitComponents.h */, + 257754B71BEE458D00737CA5 /* ASTextKitComponents.m */, 257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */, 257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */, 257754B91BEE458E00737CA5 /* ASTextNodeWordKerner.h */, - 257754BA1BEE458E00737CA5 /* ASTextKitHelpers.h */, 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */, 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */, 257754941BEE44CD00737CA5 /* ASTextKitAttributes.mm */, @@ -1301,13 +1320,13 @@ ACF6ED041B17843500DA7C62 /* ASCenterLayoutSpec.mm */, ACF6ED071B17843500DA7C62 /* ASDimension.h */, ACF6ED081B17843500DA7C62 /* ASDimension.mm */, - AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */, - AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */, ACF6ED091B17843500DA7C62 /* ASInsetLayoutSpec.h */, ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutSpec.mm */, ACF6ED0B1B17843500DA7C62 /* ASLayout.h */, ACF6ED0C1B17843500DA7C62 /* ASLayout.mm */, ACF6ED111B17843500DA7C62 /* ASLayoutable.h */, + E55D86311CA8A14000A0C26F /* ASLayoutable.mm */, + 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */, 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */, ACF6ED0D1B17843500DA7C62 /* ASLayoutSpec.h */, ACF6ED0E1B17843500DA7C62 /* ASLayoutSpec.mm */, @@ -1315,6 +1334,10 @@ ACF6ED131B17843500DA7C62 /* ASOverlayLayoutSpec.mm */, ACF6ED141B17843500DA7C62 /* ASRatioLayoutSpec.h */, ACF6ED151B17843500DA7C62 /* ASRatioLayoutSpec.mm */, + 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */, + 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */, + AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */, + AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */, 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */, AC21EC0F1B3D0BF600C8B19A /* ASStackLayoutDefines.h */, ACF6ED161B17843500DA7C62 /* ASStackLayoutSpec.h */, @@ -1322,9 +1345,6 @@ 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */, ACF6ED181B17843500DA7C62 /* ASStaticLayoutSpec.h */, ACF6ED191B17843500DA7C62 /* ASStaticLayoutSpec.mm */, - 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */, - 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */, - 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */, ); name = Layout; path = ..; @@ -1363,6 +1383,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */, + 698548631CA9E025008A345F /* ASEnvironment.h in Headers */, E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */, 257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */, A373200F1C571B730011FC94 /* ASTextNode+Beta.h in Headers */, @@ -1376,6 +1398,7 @@ 058D0A6B195D05EC00B7D73C /* _ASAsyncTransactionContainer.h in Headers */, 058D0A6D195D05EC00B7D73C /* _ASAsyncTransactionGroup.h in Headers */, 058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */, + 7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */, 058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */, 058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */, B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, @@ -1445,8 +1468,6 @@ 9CDC18CC1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */, B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */, 464052241A3F83C40061C0BA /* ASLayoutController.h in Headers */, - 9C5FA3511B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */, - 9C65A72A1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */, 292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */, 257754B61BEE44CD00737CA5 /* ASEqualityHashHelpers.h in Headers */, ACF6ED261B17843500DA7C62 /* ASLayoutSpec.h in Headers */, @@ -1470,6 +1491,7 @@ 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */, 257754C31BEE458E00737CA5 /* ASTextNodeTypes.h in Headers */, 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */, + 69E1006D1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */, AC21EC101B3D0BF600C8B19A /* ASStackLayoutDefines.h in Headers */, CC7FD9DE1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */, ACF6ED2F1B17843500DA7C62 /* ASStackLayoutSpec.h in Headers */, @@ -1483,7 +1505,7 @@ ACF6ED311B17843500DA7C62 /* ASStaticLayoutSpec.h in Headers */, 055F1A3419ABD3E3004DAFF1 /* ASTableView.h in Headers */, 251B8EF71BBB3D690087C538 /* ASCollectionDataController.h in Headers */, - 257754C11BEE458E00737CA5 /* ASTextKitHelpers.h in Headers */, + 257754C11BEE458E00737CA5 /* ASTextKitComponents.h in Headers */, B30BF6521C5964B0004FCD53 /* ASLayoutManager.h in Headers */, 0574D5E219C110940097DC25 /* ASTableViewProtocols.h in Headers */, 81EE384F1C8E94F000456208 /* ASRunLoopQueue.h in Headers */, @@ -1505,10 +1527,13 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 698C8B621CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */, + 698548641CA9E025008A345F /* ASEnvironment.h in Headers */, AC026B6A1BD57D6F00BBC17E /* ASChangeSetDataController.h in Headers */, B35062481B010EFD0018CF92 /* _AS-objc-internal.h in Headers */, 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */, B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */, + 7630FFA81C9E267E007A7C0E /* ASVideoNode.h in Headers */, B350623F1B010EFD0018CF92 /* _ASAsyncTransactionContainer.h in Headers */, B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */, 254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */, @@ -1568,6 +1593,7 @@ AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */, B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */, 254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */, + 7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */, B35062021B010EFD0018CF92 /* ASImageNode.h in Headers */, B350621F1B010EFD0018CF92 /* ASImageProtocols.h in Headers */, 430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */, @@ -1579,8 +1605,6 @@ 34EFC7691B701CE100AD841F /* ASLayoutable.h in Headers */, 9CDC18CD1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */, B35062201B010EFD0018CF92 /* ASLayoutController.h in Headers */, - 9C5FA3521B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */, - 9C65A72B1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */, B35062211B010EFD0018CF92 /* ASLayoutRangeType.h in Headers */, 34EFC76A1B701CE600AD841F /* ASLayoutSpec.h in Headers */, 34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */, @@ -1602,7 +1626,7 @@ DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */, 68B0277B1C1A79D60041016B /* ASDisplayNode+Beta.h in Headers */, B350622D1B010EFD0018CF92 /* ASScrollDirection.h in Headers */, - 254C6B751BF94DF4003EC431 /* ASTextKitHelpers.h in Headers */, + 254C6B751BF94DF4003EC431 /* ASTextKitComponents.h in Headers */, B35062081B010EFD0018CF92 /* ASScrollNode.h in Headers */, 25E327571C16819500A2170C /* ASPagerNode.h in Headers */, B35062551B010EFD0018CF92 /* ASSentinel.h in Headers */, @@ -1621,6 +1645,7 @@ 92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */, 044284FE1BAA387800D16268 /* ASStackLayoutSpecUtilities.h in Headers */, 34EFC7751B701D2400AD841F /* ASStackPositionedLayout.h in Headers */, + 69E1006E1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */, 34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */, 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */, 34EFC7731B701D0700AD841F /* ASStaticLayoutSpec.h in Headers */, @@ -1722,6 +1747,7 @@ 058D09A4195D04C000B7D73C /* Project object */ = { isa = PBXProject; attributes = { + CLASSPREFIX = AS; LastUpgradeCheck = 0720; ORGANIZATIONNAME = Facebook; TargetAttributes = { @@ -1847,11 +1873,13 @@ buildActionMask = 2147483647; files = ( 058D0A22195D050800B7D73C /* _ASAsyncTransaction.mm in Sources */, + E55D86321CA8A14000A0C26F /* ASLayoutable.mm in Sources */, 058D0A23195D050800B7D73C /* _ASAsyncTransactionContainer.m in Sources */, 058D0A24195D050800B7D73C /* _ASAsyncTransactionGroup.m in Sources */, DBDB83961C6E879900D0098C /* ASPagerFlowLayout.m in Sources */, 058D0A26195D050800B7D73C /* _ASCoreAnimationExtras.mm in Sources */, 257754B41BEE44CD00737CA5 /* ASTextKitTailTruncater.mm in Sources */, + 69E1006F1CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */, AC026B711BD57DBF00BBC17E /* _ASHierarchyChangeSet.m in Sources */, 257754BF1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m in Sources */, 058D0A18195D050800B7D73C /* _ASDisplayLayer.mm in Sources */, @@ -1895,10 +1923,9 @@ 430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */, ACF6ED231B17843500DA7C62 /* ASInsetLayoutSpec.mm in Sources */, ACF6ED4C1B17847A00DA7C62 /* ASInternalHelpers.mm in Sources */, + 698548651CA9E025008A345F /* ASEnvironment.m in Sources */, ACF6ED251B17843500DA7C62 /* ASLayout.mm in Sources */, DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */, - 9C5FA3531B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */, - 9C5FA35F1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */, 251B8EFA1BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m in Sources */, ACF6ED271B17843500DA7C62 /* ASLayoutSpec.mm in Sources */, 257754B01BEE44CD00737CA5 /* ASTextKitRenderer+TextChecking.mm in Sources */, @@ -1910,6 +1937,7 @@ CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */, ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */, 0442850F1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */, + 7A06A73A1C35F08800FE8DAA /* ASRelativeLayoutSpec.mm in Sources */, 257754921BED28F300737CA5 /* ASEqualityHashHelpers.mm in Sources */, E52405B31C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm in Sources */, 257754AB1BEE44CD00737CA5 /* ASTextKitEntityAttribute.m in Sources */, @@ -1926,7 +1954,7 @@ 9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */, 251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */, ACF6ED301B17843500DA7C62 /* ASStackLayoutSpec.mm in Sources */, - 257754BE1BEE458E00737CA5 /* ASTextKitHelpers.mm in Sources */, + 257754BE1BEE458E00737CA5 /* ASTextKitComponents.m in Sources */, 257754A91BEE44CD00737CA5 /* ASTextKitContext.mm in Sources */, ACF6ED501B17847A00DA7C62 /* ASStackPositionedLayout.mm in Sources */, ACF6ED521B17847A00DA7C62 /* ASStackUnpositionedLayout.mm in Sources */, @@ -1973,6 +2001,7 @@ 058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */, ACF6ED611B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm in Sources */, ACF6ED621B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm in Sources */, + 7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */, 254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */, 05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */, ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */, @@ -2004,6 +2033,7 @@ B35062421B010EFD0018CF92 /* _ASAsyncTransactionGroup.m in Sources */, B350624A1B010EFD0018CF92 /* _ASCoreAnimationExtras.mm in Sources */, 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */, + 698548661CA9E025008A345F /* ASEnvironment.m in Sources */, 2767E9421BB19BD600EA9B77 /* ASViewController.m in Sources */, B35062101B010EFD0018CF92 /* _ASDisplayLayer.mm in Sources */, 9C55866B1BD54A1900B50E3A /* ASAsciiArtBoxCreator.m in Sources */, @@ -2020,6 +2050,7 @@ AC47D9421B3B891B00AAEE9D /* ASCellNode.m in Sources */, 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, + E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */, B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */, 509E68641B3AEDB7009B9150 /* ASCollectionViewLayoutController.mm in Sources */, B35061F91B010EFD0018CF92 /* ASControlNode.mm in Sources */, @@ -2032,6 +2063,7 @@ 636EA1A41C7FF4EC00EE152F /* NSArray+Diffing.m in Sources */, B35062501B010EFD0018CF92 /* ASDisplayNode+DebugTiming.mm in Sources */, DEC146B91C37A16A004A0EE7 /* ASCollectionInternal.m in Sources */, + 69E100701CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */, 254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */, E5711A301C840C96009619D4 /* ASIndexedNodeContext.m in Sources */, B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */, @@ -2044,13 +2076,11 @@ B350621E1B010EFD0018CF92 /* ASHighlightOverlayLayer.mm in Sources */, B35062541B010EFD0018CF92 /* ASImageNode+CGExtras.m in Sources */, B35062031B010EFD0018CF92 /* ASImageNode.mm in Sources */, - 254C6B821BF94F8A003EC431 /* ASTextKitHelpers.mm in Sources */, + 254C6B821BF94F8A003EC431 /* ASTextKitComponents.m in Sources */, 430E7C921B4C23F100697A4C /* ASIndexPath.m in Sources */, 34EFC7601B701C8B00AD841F /* ASInsetLayoutSpec.mm in Sources */, 34EFC75E1B701BF000AD841F /* ASInternalHelpers.mm in Sources */, 34EFC7681B701CDE00AD841F /* ASLayout.mm in Sources */, - 9C5FA3541B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */, - 9C5FA3601B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */, DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */, 254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.m in Sources */, 34EFC76B1B701CEB00AD841F /* ASLayoutSpec.mm in Sources */, @@ -2073,6 +2103,7 @@ 9C8221981BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */, 34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */, 34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */, + 7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */, 34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */, DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */, AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, diff --git a/AsyncDisplayKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AsyncDisplayKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 235ea95fac..919434a625 100644 --- a/AsyncDisplayKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/AsyncDisplayKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/AsyncDisplayKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/AsyncDisplayKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..08de0be8d3 --- /dev/null +++ b/AsyncDisplayKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/AsyncDisplayKit/ASButtonNode.h b/AsyncDisplayKit/ASButtonNode.h index 22e755fe95..4363868de1 100644 --- a/AsyncDisplayKit/ASButtonNode.h +++ b/AsyncDisplayKit/ASButtonNode.h @@ -28,12 +28,12 @@ @property (nonatomic, assign) BOOL laysOutHorizontally; /** Horizontally align content (text or image). - Defaults to ASAlignmentMiddle. + Defaults to ASHorizontalAlignmentMiddle. */ @property (nonatomic, assign) ASHorizontalAlignment contentHorizontalAlignment; /** Vertically align content (text or image). - Defaults to ASAlignmentCenter. + Defaults to ASVerticalAlignmentCenter. */ @property (nonatomic, assign) ASVerticalAlignment contentVerticalAlignment; diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 89ffac944d..b673ff8a76 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -57,9 +57,10 @@ _contentSpacing = 8.0; _laysOutHorizontally = YES; - _contentHorizontalAlignment = ASAlignmentMiddle; - _contentVerticalAlignment = ASAlignmentCenter; + _contentHorizontalAlignment = ASHorizontalAlignmentMiddle; + _contentVerticalAlignment = ASVerticalAlignmentCenter; _contentEdgeInsets = UIEdgeInsetsZero; + self.accessibilityTraits = UIAccessibilityTraitButton; } return self; } @@ -102,6 +103,11 @@ - (void)setEnabled:(BOOL)enabled { [super setEnabled:enabled]; + if (enabled) { + self.accessibilityTraits = UIAccessibilityTraitButton; + } else { + self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled; + } [self updateButtonContent]; } @@ -135,7 +141,7 @@ - (void)updateImage { ASDN::MutexLocker l(_propertyLock); - + UIImage *newImage; if (self.enabled == NO && _disabledImage) { newImage = _disabledImage; @@ -170,9 +176,10 @@ } else { newTitle = _normalAttributedTitle; } - + if ((_titleNode != nil || newTitle.length > 0) && newTitle != self.titleNode.attributedString) { _titleNode.attributedString = newTitle; + self.accessibilityLabel = _titleNode.accessibilityLabel; [self setNeedsLayout]; } } @@ -271,8 +278,8 @@ - (void)setTitle:(NSString *)title withFont:(UIFont *)font withColor:(UIColor *)color forState:(ASControlState)state { NSDictionary *attributes = @{ - NSFontAttributeName: font ? font :[UIFont systemFontOfSize:[UIFont buttonFontSize]], - NSForegroundColorAttributeName : color ? color : [UIColor blackColor] + NSFontAttributeName: font ? : [UIFont systemFontOfSize:[UIFont buttonFontSize]], + NSForegroundColorAttributeName : color ? : [UIColor blackColor] }; NSAttributedString *string = [[NSAttributedString alloc] initWithString:title @@ -331,6 +338,7 @@ default: break; } + [self updateTitle]; } diff --git a/AsyncDisplayKit/ASCellNode.h b/AsyncDisplayKit/ASCellNode.h index 6c3e5001cc..e38376bee4 100644 --- a/AsyncDisplayKit/ASCellNode.h +++ b/AsyncDisplayKit/ASCellNode.h @@ -14,9 +14,9 @@ NS_ASSUME_NONNULL_BEGIN typedef NSUInteger ASCellNodeAnimation; -typedef enum : NSUInteger { - /** - * Indicates a cell has just became visible +typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) { + /** + * Indicates a cell has just became visible */ ASCellNodeVisibilityEventVisible, /** @@ -26,11 +26,11 @@ typedef enum : NSUInteger { * Use CGRectIntersect between cellFrame and scrollView.bounds to get this rectangle */ ASCellNodeVisibilityEventVisibleRectChanged, - /** - * Indicates a cell is no longer visible + /** + * Indicates a cell is no longer visible */ ASCellNodeVisibilityEventInvisible, -} ASCellNodeVisibilityEvent; +}; /** * Generic cell node. Subclass this instead of `ASDisplayNode` to use with `ASTableView` and `ASCollectionView`. @@ -51,7 +51,7 @@ typedef enum : NSUInteger { * * With this property set to YES, the main thread will be blocked until display is complete for * the cell. This is more similar to UIKit, and in fact makes AsyncDisplayKit scrolling visually - * indistinguishible from UIKit's, except being faster. + * indistinguishable from UIKit's, except being faster. * * Using this option does not eliminate all of the performance advantages of AsyncDisplayKit. * Normally, a cell has been preloading and is almost done when it reaches the screen, so the @@ -66,12 +66,12 @@ typedef enum : NSUInteger { //@property (atomic, retain) UIColor *backgroundColor; @property (nonatomic) UITableViewCellSelectionStyle selectionStyle; -/* +/** * A Boolean value that indicates whether the node is selected. */ @property (nonatomic, assign) BOOL selected; -/* +/** * A Boolean value that indicates whether the node is highlighted. */ @property (nonatomic, assign) BOOL highlighted; @@ -103,7 +103,7 @@ typedef enum : NSUInteger { * @param didLoadBlock The block that will be called after the view controller's view is loaded. * * @return An ASCellNode created using the root view of the view controller provided by the viewControllerBlock. - * The view controller's root view is resized to match the calcuated size produced during layout. + * The view controller's root view is resized to match the calculated size produced during layout. * */ - (instancetype)initWithViewControllerBlock:(ASDisplayNodeViewControllerBlock)viewControllerBlock didLoadBlock:(nullable ASDisplayNodeDidLoadBlock)didLoadBlock; diff --git a/AsyncDisplayKit/ASCollectionNode.h b/AsyncDisplayKit/ASCollectionNode.h index 49ca3ffe5a..1a8a70d98b 100644 --- a/AsyncDisplayKit/ASCollectionNode.h +++ b/AsyncDisplayKit/ASCollectionNode.h @@ -52,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Tuning parameters for a range type in the specified mode. * - * @param rangeMode The range mode to get the runing parameters for. + * @param rangeMode The range mode to get the running parameters for. * @param rangeType The range type to get the tuning parameters for. * * @returns A tuning parameter value for the given range type in the given mode. @@ -63,10 +63,10 @@ NS_ASSUME_NONNULL_BEGIN - (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType; /** - * Set the tuning parameters for a range type in the specigied mode. + * Set the tuning parameters for a range type in the specified mode. * * @param tuningParameters The tuning parameters to store for a range type. - * @param rangeMode The range mode to set the runing parameters for. + * @param rangeMode The range mode to set the running parameters for. * @param rangeType The range type to set the tuning parameters for. * * @see ASLayoutRangeMode diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index 8d1c909ad6..99a4bd0548 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -13,13 +13,12 @@ #import #import #import +#import @class ASCellNode; @class ASCollectionNode; @protocol ASCollectionDataSource; @protocol ASCollectionDelegate; -@protocol ASCollectionViewLayoutInspecting; -@protocol ASCollectionViewLayoutFacilitatorProtocol; NS_ASSUME_NONNULL_BEGIN @@ -77,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Tuning parameters for a range type in the specified mode. * - * @param rangeMode The range mode to get the runing parameters for. + * @param rangeMode The range mode to get the running parameters for. * @param rangeType The range type to get the tuning parameters for. * * @returns A tuning parameter value for the given range type in the given mode. @@ -88,10 +87,10 @@ NS_ASSUME_NONNULL_BEGIN - (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType; /** - * Set the tuning parameters for a range type in the specigied mode. + * Set the tuning parameters for a range type in the specified mode. * * @param tuningParameters The tuning parameters to store for a range type. - * @param rangeMode The range mode to set the runing parameters for. + * @param rangeMode The range mode to set the running parameters for. * @param rangeType The range type to set the tuning parameters for. * * @see ASLayoutRangeMode @@ -396,7 +395,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Indicator to lock the data source for data fetching in async mode. - * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistence or exception + * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception * due to the data access in async mode. * * @param collectionView The sender. @@ -405,7 +404,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Indicator to unlock the data source for data fetching in async mode. - * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistence or exception + * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception * due to the data access in async mode. * * @param collectionView The sender. diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index a9c79acf1c..ae1f579232 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -14,11 +14,12 @@ #import "ASCollectionDataController.h" #import "ASCollectionViewLayoutController.h" #import "ASCollectionViewFlowLayoutInspector.h" -#import "ASCollectionViewLayoutFacilitatorProtocol.h" +#import "ASDisplayNodeExtras.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" #import "ASInternalHelpers.h" #import "UICollectionViewLayout+ASConvenience.h" +#import "ASRangeControllerUpdateRangeProtocol+Beta.h" #import "_ASDisplayLayer.h" static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone; @@ -57,6 +58,36 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; @end +#pragma mark - +#pragma mark _ASCollectionViewNodeSizeUpdateContext + +/** + * This class contains all the nodes that have a new size and UICollectionView should requery them all at once. + * It is intended to be used strictly on main thread and is not thread safe. + */ +@interface _ASCollectionViewNodeSizeInvalidationContext : NSObject +/** + * It's possible that a node triggered multiple size changes before main thread has a chance to execute `requeryNodeSizes`. + * Therefore, a set is preferred here, to avoid asking ASDataController to search for index path of the same node multiple times. + */ +@property (nonatomic, strong) NSMutableSet *invalidatedNodes; +@property (nonatomic, assign) BOOL shouldAnimate; +@end + +@implementation _ASCollectionViewNodeSizeInvalidationContext + +- (instancetype)init +{ + self = [super init]; + if (self) { + _invalidatedNodes = [NSMutableSet set]; + _shouldAnimate = YES; + } + return self; +} + +@end + #pragma mark - #pragma mark ASCollectionView. @@ -78,7 +109,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; BOOL _asyncDelegateImplementsScrollviewDidScroll; BOOL _asyncDataSourceImplementsConstrainedSizeForNode; BOOL _asyncDataSourceImplementsNodeBlockForItemAtIndexPath; - BOOL _queuedNodeSizeUpdate; + _ASCollectionViewNodeSizeInvalidationContext *_queuedNodeSizeInvalidationContext; // Main thread only BOOL _isDeallocating; ASBatchContext *_batchContext; @@ -656,8 +687,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; _ignoreMaxSizeChange = NO; } else { // This actually doesn't perform an animation, but prevents the transaction block from being processed in the - // data controller's prevent animation block that would interupt an interupted relayout happening in an animation block - // ie. ASCollectionView bounds change on rotation or mutl-tasking split view resize. + // data controller's prevent animation block that would interrupt an interrupted relayout happening in an animation block + // ie. ASCollectionView bounds change on rotation or multi-tasking split view resize. [self performBatchAnimated:YES updates:^{ [_dataController relayoutAllNodes]; } completion:nil]; @@ -690,6 +721,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)scrollViewDidScroll:(UIScrollView *)scrollView { + // If a scroll happenes the current range mode needs to go to full + ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; + if (ASInterfaceStateIncludesVisible(interfaceState)) { + [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; + } + for (_ASCollectionViewCell *collectionCell in _cellsForVisibilityUpdates) { // Only nodes that respond to the selector are added to _cellsForVisibilityUpdates [[collectionCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged @@ -879,15 +916,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (ASInterfaceState)interfaceStateForRangeController:(ASRangeController *)rangeController { - ASCollectionNode *collectionNode = self.collectionNode; - if (collectionNode) { - return collectionNode.interfaceState; - } else { - // Until we can always create an associated ASCollectionNode without a retain cycle, - // we might be on our own to try to guess if we're visible. The node normally - // handles this even if it is the root / directly added to the view hierarchy. - return (self.window != nil ? ASInterfaceStateVisible : ASInterfaceStateNone); - } + return ASInterfaceStateForDisplayNode(self.collectionNode, self.window); } - (NSArray *)rangeController:(ASRangeController *)rangeController nodesAtIndexPaths:(NSArray *)indexPaths @@ -1018,24 +1047,61 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; { ASDisplayNodeAssertMainThread(); - if (!sizeChanged || _queuedNodeSizeUpdate) { + if (!sizeChanged) { return; } - _queuedNodeSizeUpdate = YES; - [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:@[[self indexPathForNode:node]] batched:NO]; - [self performSelector:@selector(requeryNodeSizes) - withObject:nil - afterDelay:0 - inModes:@[ NSRunLoopCommonModes ]]; + BOOL queued = (_queuedNodeSizeInvalidationContext != nil); + if (!queued) { + _queuedNodeSizeInvalidationContext = [[_ASCollectionViewNodeSizeInvalidationContext alloc] init]; + + __weak __typeof__(self) weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + __typeof__(self) strongSelf = weakSelf; + if (strongSelf) { + [strongSelf requeryNodeSizes]; + } + }); + } + + [_queuedNodeSizeInvalidationContext.invalidatedNodes addObject:node]; + + // Check if this node or one of its subnodes can be animated. + // If the context is already non-animated, don't bother checking this node. + if (_queuedNodeSizeInvalidationContext.shouldAnimate) { + BOOL (^shouldNotAnimateBlock)(ASDisplayNode *) = ^BOOL(ASDisplayNode * _Nonnull node) { + return node.shouldAnimateSizeChanges == NO; + }; + if (ASDisplayNodeFindFirstNode(node, shouldNotAnimateBlock) != nil) { + // One single non-animated cell node causes the whole context to be non-animated + _queuedNodeSizeInvalidationContext.shouldAnimate = NO; + } + } } // Cause UICollectionView to requery for the new size of all nodes - (void)requeryNodeSizes { - _queuedNodeSizeUpdate = NO; + ASDisplayNodeAssertMainThread(); + NSSet *nodes = _queuedNodeSizeInvalidationContext.invalidatedNodes; + NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:nodes.count]; + for (ASCellNode *node in nodes) { + NSIndexPath *indexPath = [self indexPathForNode:node]; + if (indexPath != nil) { + [indexPaths addObject:indexPath]; + } + } - [super performBatchUpdates:^{} completion:nil]; + if (indexPaths.count > 0) { + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; + + ASPerformBlockWithoutAnimation(!_queuedNodeSizeInvalidationContext.shouldAnimate, ^{ + // Perform an empty update transaction here to trigger UICollectionView to requery row sizes and layout its subviews again + [super performBatchUpdates:^{} completion:nil]; + }); + } + + _queuedNodeSizeInvalidationContext = nil; } #pragma mark - Memory Management @@ -1069,9 +1135,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; if (!visible && node.inHierarchy) { [node __exitHierarchy]; } - - // Trigger updating interfaceState for cells in case ASCollectionView becomes visible or invisible - [_rangeController visibleNodeIndexPathsDidChangeWithScrollDirection:self.scrollDirection]; + + // Updating the visible node index paths only for not range managed nodes. Range managed nodes will get their + // their update in the layout pass + if (![node supportsRangeManagedInterfaceState]) { + [_rangeController visibleNodeIndexPathsDidChangeWithScrollDirection:self.scrollDirection]; + } } #pragma mark - UICollectionView dead-end intercepts diff --git a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h index b681ceaad4..38f43b71a8 100644 --- a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h +++ b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h @@ -6,8 +6,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#ifndef ASCollectionViewLayoutFacilitatorProtocol_h -#define ASCollectionViewLayoutFacilitatorProtocol_h +#pragma once /** * This facilitator protocol is intended to help Layout to better @@ -41,5 +40,3 @@ - (void)collectionViewWillPerformBatchUpdates; @end - -#endif /* ASCollectionViewLayoutFacilitatorProtocol_h */ diff --git a/AsyncDisplayKit/ASContextTransitioning.h b/AsyncDisplayKit/ASContextTransitioning.h index 694ab6bf83..037f9a64d3 100644 --- a/AsyncDisplayKit/ASContextTransitioning.h +++ b/AsyncDisplayKit/ASContextTransitioning.h @@ -14,7 +14,7 @@ extern NSString * const ASTransitionContextToLayoutKey; @protocol ASContextTransitioning /** - @abstreact Defines if the given transition is animated + @abstract Defines if the given transition is animated */ - (BOOL)isAnimated; diff --git a/AsyncDisplayKit/ASControlNode.h b/AsyncDisplayKit/ASControlNode.h index 9f5c37e343..4bac37ff22 100644 --- a/AsyncDisplayKit/ASControlNode.h +++ b/AsyncDisplayKit/ASControlNode.h @@ -38,7 +38,7 @@ typedef NS_OPTIONS(NSUInteger, ASControlState) { ASControlStateNormal = 0, ASControlStateHighlighted = 1 << 0, // used when ASControlNode isHighlighted is set ASControlStateDisabled = 1 << 1, - ASControlStateSelected = 1 << 2, // used when ASControlNode isSeleted is set + ASControlStateSelected = 1 << 2, // used when ASControlNode isSelected is set ASControlStateReserved = 0xFF000000 // flags reserved for internal framework use }; diff --git a/AsyncDisplayKit/ASControlNode.mm b/AsyncDisplayKit/ASControlNode.mm index dde8a9e00f..4ee96d74f8 100644 --- a/AsyncDisplayKit/ASControlNode.mm +++ b/AsyncDisplayKit/ASControlNode.mm @@ -9,6 +9,8 @@ #import "ASControlNode.h" #import "ASControlNode+Subclasses.h" #import "ASThread.h" +#import "ASDisplayNodeExtras.h" +#import "ASImageNode.h" // UIControl allows dragging some distance outside of the control itself during // tracking. This value depends on the device idiom (25 or 70 points), so @@ -73,10 +75,11 @@ static BOOL _enableHitTestDebug = NO; @implementation ASControlNode { - ASDisplayNode *_debugHighlightOverlay; + ASImageNode *_debugHighlightOverlay; } #pragma mark - Lifecycle + - (id)init { if (!(self = [super init])) @@ -89,6 +92,13 @@ static BOOL _enableHitTestDebug = NO; return self; } +- (void)setUserInteractionEnabled:(BOOL)userInteractionEnabled +{ + [super setUserInteractionEnabled:userInteractionEnabled]; + self.isAccessibilityElement = userInteractionEnabled; +} + + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-missing-super-calls" @@ -243,10 +253,10 @@ static BOOL _enableHitTestDebug = NO; // add a highlight overlay node with area of ASControlNode + UIEdgeInsets self.clipsToBounds = NO; - _debugHighlightOverlay = [[ASDisplayNode alloc] init]; + _debugHighlightOverlay = [[ASImageNode alloc] init]; + _debugHighlightOverlay.zPosition = 1000; // CALayer doesn't have -moveSublayerToFront, but this will ensure we're over the top of any siblings. _debugHighlightOverlay.layerBacked = YES; - _debugHighlightOverlay.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5]; - + _debugHighlightOverlay.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.4]; [self addSubnode:_debugHighlightOverlay]; } } @@ -257,26 +267,27 @@ static BOOL _enableHitTestDebug = NO; { // Do we already have an event table for this control event? id eventKey = _ASControlNodeEventKeyForControlEvent(controlEvent); - NSMapTable *eventDispatchTable = [_controlEventDispatchTable objectForKey:eventKey]; + NSMapTable *eventDispatchTable = _controlEventDispatchTable[eventKey]; // Create it if necessary. if (!eventDispatchTable) { // Create the dispatch table for this event. eventDispatchTable = [NSMapTable weakToStrongObjectsMapTable]; - [_controlEventDispatchTable setObject:eventDispatchTable forKey:eventKey]; + _controlEventDispatchTable[eventKey] = eventDispatchTable; } // Have we seen this target before for this event? - NSMutableArray *targetActions = [eventDispatchTable objectForKey:target]; + NSMutableSet *targetActions = [eventDispatchTable objectForKey:target]; if (!targetActions) { - // Nope. Create an actions array for it. - targetActions = [[NSMutableArray alloc] initWithCapacity:kASControlNodeActionDispatchTableInitialCapacity]; // enough to handle common types without re-hashing the dictionary when adding entries. + // Nope. Create an action set for it. + targetActions = [[NSMutableSet alloc] initWithCapacity:kASControlNodeActionDispatchTableInitialCapacity]; // enough to handle common types without re-hashing the dictionary when adding entries. [eventDispatchTable setObject:targetActions forKey:target]; } // Add the action message. - // Note that bizarrely enough UIControl (at least according to the docs) supports duplicate target-action pairs for a particular control event, so we replicate that behavior. + // UIControl does not support duplicate target-action-events entries, so we replicate that behavior. + // See: https://github.com/facebook/AsyncDisplayKit/files/205466/DuplicateActionsTest.playground.zip [targetActions addObject:NSStringFromSelector(action)]; }); @@ -291,7 +302,7 @@ static BOOL _enableHitTestDebug = NO; ASDN::MutexLocker l(_controlLock); // Grab the event dispatch table for this event. - NSMapTable *eventDispatchTable = [_controlEventDispatchTable objectForKey:_ASControlNodeEventKeyForControlEvent(controlEvent)]; + NSMapTable *eventDispatchTable = _controlEventDispatchTable[_ASControlNodeEventKeyForControlEvent(controlEvent)]; if (!eventDispatchTable) return nil; @@ -328,7 +339,7 @@ static BOOL _enableHitTestDebug = NO; { // Grab the dispatch table for this event (if we have it). id eventKey = _ASControlNodeEventKeyForControlEvent(controlEvent); - NSMapTable *eventDispatchTable = [_controlEventDispatchTable objectForKey:eventKey]; + NSMapTable *eventDispatchTable = _controlEventDispatchTable[eventKey]; if (!eventDispatchTable) return; @@ -361,7 +372,7 @@ static BOOL _enableHitTestDebug = NO; if (!target) { // Look at every target, removing target-pairs that have action (or all of its actions). - for (id aTarget in eventDispatchTable) + for (id aTarget in [eventDispatchTable copy]) removeActionFromTarget(aTarget, action); } else @@ -381,7 +392,7 @@ static BOOL _enableHitTestDebug = NO; (ASControlNodeEvent controlEvent) { // Use a copy to itereate, the action perform could call remove causing a mutation crash. - NSMapTable *eventDispatchTable = [[_controlEventDispatchTable objectForKey:_ASControlNodeEventKeyForControlEvent(controlEvent)] copy]; + NSMapTable *eventDispatchTable = [_controlEventDispatchTable[_ASControlNodeEventKeyForControlEvent(controlEvent)] copy]; // For each target interested in this event... for (id target in eventDispatchTable) @@ -413,7 +424,7 @@ static BOOL _enableHitTestDebug = NO; id _ASControlNodeEventKeyForControlEvent(ASControlNodeEvent controlEvent) { - return [NSNumber numberWithInteger:controlEvent]; + return @(controlEvent); } void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, void (^block)(ASControlNodeEvent anEvent)) @@ -453,12 +464,35 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v [super layout]; if (_debugHighlightOverlay) { - UIEdgeInsets insets = [self hitTestSlop]; - CGRect controlNodeRect = self.bounds; - _debugHighlightOverlay.frame = CGRectMake(controlNodeRect.origin.x + insets.left, - controlNodeRect.origin.y + insets.top, - controlNodeRect.size.width - insets.left - insets.right, - controlNodeRect.size.height - insets.top - insets.bottom); + + // Even if our parents don't have clipsToBounds set and would allow us to display the debug overlay, UIKit event delivery (hitTest:) + // will not search sub-hierarchies if one of our parents does not return YES for pointInside:. In such a scenario, hitTestSlop + // may not be able to expand the tap target as much as desired without also setting some hitTestSlop on the limiting parents. + CGRect intersectRect = UIEdgeInsetsInsetRect(self.bounds, [self hitTestSlop]); + CALayer *layer = self.layer; + CALayer *intersectLayer = layer; + CALayer *intersectSuperlayer = layer.superlayer; + + // Stop climbing if we encounter a UIScrollView, as its offset bounds origin may make it seem like our events will be clipped when + // scrolling will actually reveal them (because this process will not re-run due to scrolling) + while (intersectSuperlayer && ![intersectSuperlayer.delegate respondsToSelector:@selector(contentOffset)]) { + // Get our parent's tappable bounds. If the parent has an associated node, consider hitTestSlop, as it will extend its pointInside:. + CGRect parentHitRect = intersectSuperlayer.bounds; + ASDisplayNode *parentNode = ASLayerToDisplayNode(intersectSuperlayer); + if (parentNode) { + parentHitRect = UIEdgeInsetsInsetRect(parentHitRect, [parentNode hitTestSlop]); + } + + // Convert our current rectangle to parent coordinates, and intersect with the parent's hit rect. + CGRect intersectRectInParentCoordinates = [intersectSuperlayer convertRect:intersectRect fromLayer:intersectLayer]; + intersectRect = CGRectIntersection(parentHitRect, intersectRectInParentCoordinates); + + // Advance up the tree. + intersectLayer = intersectSuperlayer; + intersectSuperlayer = intersectLayer.superlayer; + } + + _debugHighlightOverlay.frame = [intersectLayer convertRect:intersectRect toLayer:layer]; } } @@ -467,5 +501,4 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v _enableHitTestDebug = enable; } - @end diff --git a/AsyncDisplayKit/ASDisplayNode+Beta.h b/AsyncDisplayKit/ASDisplayNode+Beta.h index 1ea3d3376f..4bb108b66a 100644 --- a/AsyncDisplayKit/ASDisplayNode+Beta.h +++ b/AsyncDisplayKit/ASDisplayNode+Beta.h @@ -91,4 +91,16 @@ ASDISPLAYNODE_EXTERN_C_END shouldMeasureAsync:(BOOL)shouldMeasureAsync measurementCompletion:(void(^)())completion; + +/** + * @abstract Currently used by ASNetworkImageNode and ASMultiplexImageNode to allow their placeholders to stay if they are loading an image from the network. + * Otherwise, a display pass is scheduled and completes, but does not actually draw anything - and ASDisplayNode considers the element finished. + */ +- (BOOL)placeholderShouldPersist; + +/** + * @abstract Cancels all performing layout transitions. Can be called on any thread. + */ +- (void)cancelLayoutTransitionsInProgress; + @end diff --git a/AsyncDisplayKit/ASDisplayNode+Subclasses.h b/AsyncDisplayKit/ASDisplayNode+Subclasses.h index e369b5c18a..d7dad4cbc8 100644 --- a/AsyncDisplayKit/ASDisplayNode+Subclasses.h +++ b/AsyncDisplayKit/ASDisplayNode+Subclasses.h @@ -206,6 +206,8 @@ NS_ASSUME_NONNULL_BEGIN * * @discussion Subclasses may override this method to be notified when display (asynchronous or synchronous) is * about to begin. + * + * @note Called on the main thread only */ - (void)displayWillStart ASDISPLAYNODE_REQUIRES_SUPER; @@ -214,6 +216,8 @@ NS_ASSUME_NONNULL_BEGIN * * @discussion Subclasses may override this method to be notified when display (asynchronous or synchronous) has * completed. + * + * @note Called on the main thread only */ - (void)displayDidFinish ASDISPLAYNODE_REQUIRES_SUPER; @@ -227,6 +231,11 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState ASDISPLAYNODE_REQUIRES_SUPER; +/** + * @abstract Called whenever the visiblity of the node changed. + * + * @discussion Subclasses may use this to monitor when they become visible. + */ - (void)visibilityDidChange:(BOOL)isVisible ASDISPLAYNODE_REQUIRES_SUPER; /** diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 2f67dc170c..83ff98bc26 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -177,7 +177,7 @@ NS_ASSUME_NONNULL_BEGIN * @warning The first access to it must be on the main thread, and should only be used on the main thread thereafter as * well. */ -@property (nonatomic, readonly, retain) UIView *view; +@property (nonatomic, readonly, strong) UIView *view; /** * @abstract Returns whether a node's backing view or layer is loaded. @@ -202,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN * @warning The first access to it must be on the main thread, and should only be used on the main thread thereafter as * well. */ -@property (nonatomic, readonly, retain) CALayer * _Nonnull layer; +@property (nonatomic, readonly, strong) CALayer * _Nonnull layer; /** * @abstract Returns the Interface State of the node. @@ -351,7 +351,7 @@ NS_ASSUME_NONNULL_BEGIN /** * @abstract The receiver's immediate subnodes. */ -@property (nonatomic, readonly, retain) NSArray *subnodes; +@property (nonatomic, readonly, copy) NSArray *subnodes; /** * @abstract The receiver's supernode. @@ -428,6 +428,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign) BOOL displaySuspended; +/** + * @abstract Whether size changes should be animated. Default to YES. + */ +@property (nonatomic, assign) BOOL shouldAnimateSizeChanges; + /** * @abstract Prevent the node and its descendants' layer from displaying. * @@ -617,7 +622,7 @@ NS_ASSUME_NONNULL_END */ - (void)setNeedsLayout; -@property (atomic, retain, nullable) id contents; // default=nil +@property (atomic, strong, nullable) id contents; // default=nil @property (atomic, assign) BOOL clipsToBounds; // default==NO @property (atomic, getter=isOpaque) BOOL opaque; // default==YES @@ -645,9 +650,9 @@ NS_ASSUME_NONNULL_END * @discussion In contrast to UIView, setting a transparent color will not set opaque = NO. * This only affects nodes that implement +drawRect like ASTextNode. */ -@property (atomic, retain, nullable) UIColor *backgroundColor; // default=nil +@property (atomic, strong, nullable) UIColor *backgroundColor; // default=nil -@property (atomic, retain, null_resettable) UIColor *tintColor; // default=Blue +@property (atomic, strong, null_resettable) UIColor *tintColor; // default=Blue - (void)tintColorDidChange; // Notifies the node when the tintColor has changed. /** @@ -697,7 +702,7 @@ NS_ASSUME_NONNULL_END @property (nullable, atomic, copy) NSString *accessibilityValue; @property (atomic, assign) UIAccessibilityTraits accessibilityTraits; @property (atomic, assign) CGRect accessibilityFrame; -@property (nullable, atomic, retain) NSString *accessibilityLanguage; +@property (nullable, atomic, strong) NSString *accessibilityLanguage; @property (atomic, assign) BOOL accessibilityElementsHidden; @property (atomic, assign) BOOL accessibilityViewIsModal; @property (atomic, assign) BOOL shouldGroupAccessibilityChildren; diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index d16479a5d5..ade7937883 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -10,7 +10,6 @@ #import "ASDisplayNode+Subclasses.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" -#import "ASLayoutOptionsPrivate.h" #import #import @@ -25,6 +24,7 @@ #import "ASDisplayNodeExtras.h" #import "ASEqualityHelpers.h" #import "ASRunLoopQueue.h" +#import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -60,7 +60,7 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS @implementation ASDisplayNode // these dynamic properties all defined in ASLayoutOptionsPrivate.m -@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition; @synthesize name = _name; @synthesize preferredFrameSize = _preferredFrameSize; @synthesize isFinalLayoutable = _isFinalLayoutable; @@ -95,7 +95,7 @@ _ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node) } /** - * Returns ASDisplayNodeFlags for the givern class/instance. instance MAY BE NIL. + * Returns ASDisplayNodeFlags for the given class/instance. instance MAY BE NIL. * * @param c the class, required * @param instance the instance, which may be nil. (If so, the class is inspected instead) @@ -114,6 +114,7 @@ static struct ASDisplayNodeFlags GetASDisplayNodeFlags(Class c, ASDisplayNode *i flags.isInHierarchy = NO; flags.displaysAsynchronously = YES; + flags.shouldAnimateSizeChanges = YES; flags.implementsDrawRect = ([c respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0); flags.implementsImageDisplay = ([c respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0); if (instance) { @@ -131,7 +132,7 @@ static struct ASDisplayNodeFlags GetASDisplayNodeFlags(Class c, ASDisplayNode *i /** * Returns ASDisplayNodeMethodOverrides for the given class * - * @param c the class, requireed. + * @param c the class, required. * * @return ASDisplayNodeMethodOverrides. */ @@ -197,6 +198,12 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) class_replaceMethod(self, @selector(_staticInitialize), staticInitialize, "v:@"); } ++ (void)load +{ + // Ensure this value is cached on the main thread before needed in the background. + ASScreenScale(); +} + + (BOOL)layerBackedNodesEnabled { return YES; @@ -224,7 +231,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) if (isQueueDrained) { [[NSNotificationCenter defaultCenter] postNotificationName:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil - userInfo:@{ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp: [NSNumber numberWithDouble:timestamp]}]; + userInfo:@{ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp: @(timestamp)}]; } }]; }); @@ -245,6 +252,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _contentsScaleForDisplay = ASScreenScale(); _displaySentinel = [[ASSentinel alloc] init]; _preferredFrameSize = CGSizeZero; + + _environmentState = ASEnvironmentStateMakeDefault(); } - (id)init @@ -330,7 +339,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) - (void)dealloc { ASDisplayNodeAssertMainThread(); - + // Synchronous nodes may not be able to call the hierarchy notifications, so only enforce for regular nodes. + ASDisplayNodeAssert(_flags.synchronous || !ASInterfaceStateIncludesVisible(_interfaceState), @"Node should always be marked invisible before deallocating; interfaceState: %lu, %@", (unsigned long)_interfaceState, self); + self.asyncLayer.asyncDelegate = nil; _view.asyncdisplaykit_node = nil; _layer.asyncdisplaykit_node = nil; @@ -419,6 +430,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) { CALayer *layer; ASDN::MutexLocker l(_propertyLock); + ASDisplayNodeAssert(_flags.layerBacked, @"_layerToLoad is only for layer-backed nodes"); if (_layerBlock) { layer = _layerBlock(); @@ -474,10 +486,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) TIME_SCOPED(_debugTimeForDidLoad); [self __didLoad]; } - - if (self.placeholderEnabled) { - [self _setupPlaceholderLayer]; - } } - (UIView *)view @@ -589,14 +597,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) return _layout; } - if ([self _hasTransitionsInProgress]) { - // Invalidate transition sentinel to cancel transitions in progress - [self _invalidateTransitionSentinel]; - // Tell subnodes to exit layout pending state and clear related properties - ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { - node.hierarchyState &= (~ASHierarchyStateLayoutPending); - }); - } + [self cancelLayoutTransitionsInProgress]; ASLayout *previousLayout = _layout; ASSizeRange previousConstrainedSize = _constrainedSize; @@ -631,8 +632,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) return NO; } - if (ASHierarchyStateIncludesLayoutPending(_hierarchyState) && constrainedSize.transitionID != _pendingTransitionID) { - return NO; + if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) { + ASLayoutableContext context = ASLayoutableGetCurrentContext(); + if (ASLayoutableContextIsNull(context) || _pendingTransitionID != context.transitionID) { + return NO; + } } // only calculate the size if @@ -669,8 +673,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) } int32_t transitionID = [self _newTransitionID]; - constrainedSize.transitionID = transitionID; - + ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { ASDisplayNodeAssert([node _hasTransitionsInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one."); node.hierarchyState |= ASHierarchyStateLayoutPending; @@ -680,6 +683,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) void (^transitionBlock)() = ^{ ASLayout *newLayout; { + ASLayoutableSetCurrentContext(ASLayoutableContextMake(transitionID, NO)); + ASDN::MutexLocker l(_propertyLock); BOOL disableImplicitHierarchyManagement = self.usesImplicitHierarchyManagement == NO; self.usesImplicitHierarchyManagement = YES; // Temporary flag for 1.9.x @@ -687,6 +692,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) if (disableImplicitHierarchyManagement) { self.usesImplicitHierarchyManagement = NO; // Temporary flag for 1.9.x } + + ASLayoutableClearCurrentContext(); } if ([self _shouldAbortTransitionWithID:transitionID]) { @@ -694,12 +701,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) } ASPerformBlockOnMainThread(^{ + // Grab _propertyLock here to make sure this transition isn't invalidated + // right after it passed the validation test and before it proceeds + ASDN::MutexLocker l(_propertyLock); + if ([self _shouldAbortTransitionWithID:transitionID]) { return; } - ASDN::MutexLocker l(_propertyLock); - ASLayout *previousLayout = _layout; ASSizeRange previousConstrainedSize = _constrainedSize; [self applyLayout:newLayout constrainedSize:constrainedSize layoutContext:nil]; @@ -742,17 +751,20 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) ASDN::MutexLocker l(_propertyLock); [self calculatedLayoutDidChange]; - // we generate placeholders at measureWithSizeRange: time so that a node is guaranteed - // to have a placeholder ready to go. Also, if a node has no size it should not have a placeholder - if (self.placeholderEnabled && [self _displaysAsynchronously] && - _layout.size.width > 0.0 && _layout.size.height > 0.0) { + // We generate placeholders at measureWithSizeRange: time so that a node is guaranteed to have a placeholder ready to go. + // This is also because measurement is usually asynchronous, but placeholders need to be set up synchronously. + // First measurement is guaranteed to be before the node is onscreen, so we can create the image async. but still have it appear sync. + if (_placeholderEnabled && [self _displaysAsynchronously] && self.contents == nil) { + + // Zero-sized nodes do not require a placeholder. + CGSize layoutSize = (_layout ? _layout.size : CGSizeZero); + if (CGSizeEqualToSize(layoutSize, CGSizeZero)) { + return; + } + if (!_placeholderImage) { _placeholderImage = [self placeholderImage]; } - - if (_placeholderLayer) { - [self _setupPlaceholderLayerContents]; - } } } @@ -762,12 +774,25 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // subclass override } +- (void)cancelLayoutTransitionsInProgress +{ + ASDN::MutexLocker l(_propertyLock); + if ([self _hasTransitionsInProgress]) { + // Invalidate transition sentinel to cancel transitions in progress + [self _invalidateTransitionSentinel]; + // Tell subnodes to exit layout pending state and clear related properties + ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { + node.hierarchyState &= (~ASHierarchyStateLayoutPending); + }); + } +} + #pragma mark - Layout Transition - (BOOL)usesImplicitHierarchyManagement { ASDN::MutexLocker l(_propertyLock); - return _usesImplicitHierarchyManagement ?: [[self class] usesImplicitHierarchyManagement]; + return _usesImplicitHierarchyManagement ? : [[self class] usesImplicitHierarchyManagement]; } - (void)setUsesImplicitHierarchyManagement:(BOOL)value @@ -812,11 +837,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) - (BOOL)_displaysAsynchronously { ASDisplayNodeAssertThreadAffinity(self); - if (self.isSynchronous) { - return NO; - } else { - return _flags.displaysAsynchronously; - } + return _flags.synchronous == NO && _flags.displaysAsynchronously; } - (void)setDisplaysAsynchronously:(BOOL)displaysAsynchronously @@ -1007,13 +1028,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) { ASDisplayNodeAssertMainThread(); ASDN::MutexLocker l(_propertyLock); - if (CGRectEqualToRect(self.bounds, CGRectZero)) { + CGRect bounds = self.bounds; + if (CGRectEqualToRect(bounds, CGRectZero)) { // Performing layout on a zero-bounds view often results in frame calculations // with negative sizes after applying margins, which will cause // measureWithSizeRange: on subnodes to assert. return; } - _placeholderLayer.frame = self.bounds; + _placeholderLayer.frame = bounds; [self layout]; [self layoutDidFinish]; } @@ -1061,7 +1083,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo { ASDisplayNodeAssertThreadAffinity(self); // Get root node of the accessible node hierarchy, if node not specified - node = node ? node : ASDisplayNodeUltimateParentOfNode(self); + node = node ? : ASDisplayNodeUltimateParentOfNode(self); // Calculate transform to map points between coordinate spaces CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(node, self); @@ -1076,7 +1098,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo { ASDisplayNodeAssertThreadAffinity(self); // Get root node of the accessible node hierarchy, if node not specified - node = node ? node : ASDisplayNodeUltimateParentOfNode(self); + node = node ? : ASDisplayNodeUltimateParentOfNode(self); // Calculate transform to map points between coordinate spaces CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(self, node); @@ -1091,7 +1113,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo { ASDisplayNodeAssertThreadAffinity(self); // Get root node of the accessible node hierarchy, if node not specified - node = node ? node : ASDisplayNodeUltimateParentOfNode(self); + node = node ? : ASDisplayNodeUltimateParentOfNode(self); // Calculate transform to map points between coordinate spaces CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(node, self); @@ -1106,7 +1128,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo { ASDisplayNodeAssertThreadAffinity(self); // Get root node of the accessible node hierarchy, if node not specified - node = node ? node : ASDisplayNodeUltimateParentOfNode(self); + node = node ? : ASDisplayNodeUltimateParentOfNode(self); // Calculate transform to map points between coordinate spaces CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(self, node); @@ -1528,13 +1550,14 @@ static NSInteger incrementIfFound(NSInteger i) { ASDisplayNodeAssertMainThread(); ASDisplayNodeAssert(!_flags.isEnteringHierarchy, @"Should not cause recursive __enterHierarchy"); - // Profiling has shown that locking this method is benificial, so each of the property accesses don't have to lock and unlock. + // Profiling has shown that locking this method is beneficial, so each of the property accesses don't have to lock and unlock. ASDN::MutexLocker l(_propertyLock); - if (!self.inHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) { - self.inHierarchy = YES; + if (!_flags.isInHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) { _flags.isEnteringHierarchy = YES; - if (self.shouldRasterizeDescendants) { + _flags.isInHierarchy = YES; + + if (_flags.shouldRasterizeDescendants) { // Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants. [self _recursiveWillEnterHierarchy]; } else { @@ -1542,9 +1565,20 @@ static NSInteger incrementIfFound(NSInteger i) { } _flags.isEnteringHierarchy = NO; - CALayer *layer = self.layer; - if (!layer.contents) { + + // If we don't have contents finished drawing by the time we are on screen, immediately add the placeholder (if it is enabled and we do have something to draw). + if (self.contents == nil) { + CALayer *layer = self.layer; [layer setNeedsDisplay]; + + if ([self _shouldHavePlaceholderLayer]) { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + [self _setupPlaceholderLayerIfNeeded]; + _placeholderLayer.opacity = 1.0; + [CATransaction commit]; + [layer addSublayer:_placeholderLayer]; + } } } } @@ -1554,21 +1588,38 @@ static NSInteger incrementIfFound(NSInteger i) { ASDisplayNodeAssertMainThread(); ASDisplayNodeAssert(!_flags.isExitingHierarchy, @"Should not cause recursive __exitHierarchy"); - // Profiling has shown that locking this method is benificial, so each of the property accesses don't have to lock and unlock. + // Profiling has shown that locking this method is beneficial, so each of the property accesses don't have to lock and unlock. ASDN::MutexLocker l(_propertyLock); - if (self.inHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) { - self.inHierarchy = NO; + if (_flags.isInHierarchy && !_flags.visibilityNotificationsDisabled && ![self __selfOrParentHasVisibilityNotificationsDisabled]) { + _flags.isExitingHierarchy = YES; + _flags.isInHierarchy = NO; [self.asyncLayer cancelAsyncDisplay]; - _flags.isExitingHierarchy = YES; - if (self.shouldRasterizeDescendants) { + if (_flags.shouldRasterizeDescendants) { // Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants. [self _recursiveDidExitHierarchy]; } else { [self didExitHierarchy]; } + + // This case is important when tearing down hierarchies. We must deliver a visibilityDidChange:NO callback, as part our API guarantee that this method can be used for + // things like data analytics about user content viewing. We cannot call the method in the dealloc as any incidental retain operations in client code would fail. + // Additionally, it may be that a Standard UIView which is containing us is moving between hierarchies, and we should not send the call if we will be re-added in the + // same runloop. Strategy: strong reference (might be the last!), wait one runloop, and confirm we are still outside the hierarchy (both layer-backed and view-backed). + // TODO: This approach could be optimized by only performing the dispatch for root elements + recursively apply the interface state change. This would require a closer + // integration with _ASDisplayLayer to ensure that the superlayer pointer has been cleared by this stage (to check if we are root or not), or a different delegate call. + + if (ASInterfaceStateIncludesVisible(_interfaceState)) { + dispatch_async(dispatch_get_main_queue(), ^{ + ASDN::MutexLocker l(_propertyLock); + if (!_flags.isInHierarchy && ASInterfaceStateIncludesVisible(_interfaceState)) { + self.interfaceState = (_interfaceState & ~ASInterfaceStateVisible); + } + }); + } + _flags.isExitingHierarchy = NO; } } @@ -1657,7 +1708,7 @@ static NSInteger incrementIfFound(NSInteger i) { // The node sending the message should usually be passed as the parameter, similar to the delegation pattern. - (void)_pendingNodeWillDisplay:(ASDisplayNode *)node { - ASDN::MutexLocker l(_propertyLock); + ASDisplayNodeAssertMainThread(); if (!_pendingDisplayNodes) { _pendingDisplayNodes = [[NSMutableSet alloc] init]; @@ -1670,57 +1721,67 @@ static NSInteger incrementIfFound(NSInteger i) { // The node sending the message should usually be passed as the parameter, similar to the delegation pattern. - (void)_pendingNodeDidDisplay:(ASDisplayNode *)node { - ASDN::MutexLocker l(_propertyLock); + ASDisplayNodeAssertMainThread(); [_pendingDisplayNodes removeObject:node]; - // only trampoline if there is a placeholder and nodes are done displaying - if ([self _pendingDisplayNodesHaveFinished] && _placeholderLayer.superlayer) { - dispatch_async(dispatch_get_main_queue(), ^{ - void (^cleanupBlock)() = ^{ - [self _tearDownPlaceholderLayer]; - }; + if (_pendingDisplayNodes.count == 0 && _placeholderLayer.superlayer && ![self placeholderShouldPersist]) { + void (^cleanupBlock)() = ^{ + [_placeholderLayer removeFromSuperlayer]; + }; - if (_placeholderFadeDuration > 0.0 && ASInterfaceStateIncludesVisible(self.interfaceState)) { - [CATransaction begin]; - [CATransaction setCompletionBlock:cleanupBlock]; - [CATransaction setAnimationDuration:_placeholderFadeDuration]; - _placeholderLayer.opacity = 0.0; - [CATransaction commit]; - } else { - cleanupBlock(); - } - }); + if (_placeholderFadeDuration > 0.0 && ASInterfaceStateIncludesVisible(self.interfaceState)) { + [CATransaction begin]; + [CATransaction setCompletionBlock:cleanupBlock]; + [CATransaction setAnimationDuration:_placeholderFadeDuration]; + _placeholderLayer.opacity = 0.0; + [CATransaction commit]; + } else { + cleanupBlock(); + } } } -// Helper method to check that all nodes that the current node is waiting to display are finished -// Use this method to check to remove any placeholder layers -- (BOOL)_pendingDisplayNodesHaveFinished -{ - return _pendingDisplayNodes.count == 0; -} - // Helper method to summarize whether or not the node run through the display process - (BOOL)__implementsDisplay { - return _flags.implementsDrawRect == YES || _flags.implementsImageDisplay == YES || self.shouldRasterizeDescendants || _flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay; + return _flags.implementsDrawRect || _flags.implementsImageDisplay || _flags.shouldRasterizeDescendants || _flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay; } -- (void)_setupPlaceholderLayer +- (BOOL)placeholderShouldPersist +{ + return NO; +} + +- (BOOL)_shouldHavePlaceholderLayer +{ + return (_placeholderEnabled && [self __implementsDisplay]); +} + +- (void)_setupPlaceholderLayerIfNeeded { ASDisplayNodeAssertMainThread(); - _placeholderLayer = [CALayer layer]; - // do not set to CGFLOAT_MAX in the case that something needs to be overtop the placeholder - _placeholderLayer.zPosition = 9999.0; -} + if (!_placeholderLayer) { + _placeholderLayer = [CALayer layer]; + // do not set to CGFLOAT_MAX in the case that something needs to be overtop the placeholder + _placeholderLayer.zPosition = 9999.0; + } -- (void)_tearDownPlaceholderLayer -{ - ASDisplayNodeAssertMainThread(); - - [_placeholderLayer removeFromSuperlayer]; + if (_placeholderLayer.contents == nil) { + if (!_placeholderImage) { + _placeholderImage = [self placeholderImage]; + } + if (_placeholderImage) { + BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(_placeholderImage.capInsets, UIEdgeInsetsZero); + if (stretchable) { + ASDisplayNodeSetupLayerContentsWithResizableImage(_placeholderLayer, _placeholderImage); + } else { + _placeholderLayer.contentsScale = self.contentsScale; + _placeholderLayer.contents = (id)_placeholderImage.CGImage; + } + } + } } void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) @@ -1795,6 +1856,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(_propertyLock); if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) { ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize]; + layoutSpec.parent = self; // This causes upward propogation of any non-default layoutable values. layoutSpec.isMutable = NO; ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. @@ -1859,6 +1921,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(_propertyLock); if (! CGSizeEqualToSize(_preferredFrameSize, preferredFrameSize)) { _preferredFrameSize = preferredFrameSize; + self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(_preferredFrameSize), ASRelativeSizeMakeWithCGSize(_preferredFrameSize)); [self invalidateCalculatedLayout]; } } @@ -1938,13 +2001,11 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) _placeholderImage = nil; } -// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or exitInterfaceState: - (void)recursivelyClearContents { - for (ASDisplayNode *subnode in self.subnodes) { - [subnode recursivelyClearContents]; - } - [self clearContents]; + ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode * _Nonnull node) { + [node clearContents]; + }); } - (void)fetchData @@ -1959,13 +2020,11 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) } } -// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or enterInterfaceState: - (void)recursivelyFetchData { - for (ASDisplayNode *subnode in self.subnodes) { - [subnode recursivelyFetchData]; - } - [self fetchData]; + ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode * _Nonnull node) { + [node fetchData]; + }); } - (void)clearFetchedData @@ -1973,17 +2032,16 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) // subclass override } -// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or exitInterfaceState: - (void)recursivelyClearFetchedData { - for (ASDisplayNode *subnode in self.subnodes) { - [subnode recursivelyClearFetchedData]; - } - [self clearFetchedData]; + ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode * _Nonnull node) { + [node clearFetchedData]; + }); } - (void)visibilityDidChange:(BOOL)isVisible { + // subclass override } /** @@ -1992,7 +2050,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) */ - (BOOL)supportsRangeManagedInterfaceState { - return (_hierarchyState & ASHierarchyStateRangeManaged); + return ASHierarchyStateIncludesRangeManaged(_hierarchyState); } - (ASInterfaceState)interfaceState @@ -2085,11 +2143,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) BOOL wasVisible = ASInterfaceStateIncludesVisible(oldState); if (nowVisible != wasVisible) { - if (nowVisible) { - [self visibilityDidChange:YES]; - } else { - [self visibilityDidChange:NO]; - } + [self visibilityDidChange:nowVisible]; } [self interfaceStateDidChange:newState fromState:oldState]; @@ -2178,7 +2232,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) // Leaving layout pending state, reset related properties { ASDN::MutexLocker l(_propertyLock); - _pendingTransitionID = 0; + _pendingTransitionID = ASLayoutableContextInvalidTransitionID; _pendingLayoutContext = nil; } } @@ -2260,34 +2314,18 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) - (void)displayWillStart { + ASDisplayNodeAssertMainThread(); + // in case current node takes longer to display than it's subnodes, treat it as a dependent node [self _pendingNodeWillDisplay:self]; [_supernode subnodeDisplayWillStart:self]; - - if (_placeholderImage && _placeholderLayer && self.layer.contents == nil) { - [CATransaction begin]; - [CATransaction setDisableActions:YES]; - [self _setupPlaceholderLayerContents]; - _placeholderLayer.opacity = 1.0; - [CATransaction commit]; - [self.layer addSublayer:_placeholderLayer]; - } -} - -- (void)_setupPlaceholderLayerContents -{ - BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(_placeholderImage.capInsets, UIEdgeInsetsZero); - if (stretchable) { - ASDisplayNodeSetupLayerContentsWithResizableImage(_placeholderLayer, _placeholderImage); - } else { - _placeholderLayer.contentsScale = self.contentsScale; - _placeholderLayer.contents = (id)_placeholderImage.CGImage; - } } - (void)displayDidFinish { + ASDisplayNodeAssertMainThread(); + [self _pendingNodeDidDisplay:self]; [_supernode subnodeDisplayDidFinish:self]; @@ -2494,14 +2532,31 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer, self.asyncLayer.displaySuspended = flag; if ([self __implementsDisplay]) { - if (flag) { - [_supernode subnodeDisplayDidFinish:self]; - } else { - [_supernode subnodeDisplayWillStart:self]; - } + // Display start and finish methods needs to happen on the main thread + ASPerformBlockOnMainThread(^{ + if (flag) { + [_supernode subnodeDisplayDidFinish:self]; + } else { + [_supernode subnodeDisplayWillStart:self]; + } + }); } } +- (BOOL)shouldAnimateSizeChanges +{ + ASDisplayNodeAssertThreadAffinity(self); + ASDN::MutexLocker l(_propertyLock); + return _flags.shouldAnimateSizeChanges; +} + +-(void)setShouldAnimateSizeChanges:(BOOL)shouldAnimateSizeChanges +{ + ASDisplayNodeAssertThreadAffinity(self); + ASDN::MutexLocker l(_propertyLock); + _flags.shouldAnimateSizeChanges = shouldAnimateSizeChanges; +} + static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (void)setDrawingPriority:(NSInteger)drawingPriority @@ -2513,7 +2568,7 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; objc_setAssociatedObject(self, ASDisplayNodeDrawingPriorityKey, nil, OBJC_ASSOCIATION_ASSIGN); } else { _flags.hasCustomDrawingPriority = YES; - objc_setAssociatedObject(self, ASDisplayNodeDrawingPriorityKey, [NSNumber numberWithInteger:drawingPriority], OBJC_ASSOCIATION_RETAIN); + objc_setAssociatedObject(self, ASDisplayNodeDrawingPriorityKey, @(drawingPriority), OBJC_ASSOCIATION_RETAIN); } } @@ -2615,6 +2670,37 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; return self; } +#pragma mark - ASEnvironment + +- (ASEnvironmentState)environmentState +{ + return _environmentState; +} + +- (void)setEnvironmentState:(ASEnvironmentState)environmentState +{ + _environmentState = environmentState; +} + +- (ASDisplayNode *)parent +{ + return self.supernode; +} + +- (NSArray *)children +{ + return self.subnodes; +} + +- (BOOL)supportsUpwardPropagation +{ + return YES; +} + +ASEnvironmentLayoutOptionsForwarding +ASEnvironmentLayoutExtensibilityForwarding + + #if TARGET_OS_TV #pragma mark - UIFocusEnvironment Protocol (tvOS) diff --git a/AsyncDisplayKit/ASDisplayNodeExtras.h b/AsyncDisplayKit/ASDisplayNodeExtras.h index 319b5ff62d..171d6f381f 100644 --- a/AsyncDisplayKit/ASDisplayNodeExtras.h +++ b/AsyncDisplayKit/ASDisplayNodeExtras.h @@ -59,6 +59,11 @@ NS_ASSUME_NONNULL_BEGIN ASDISPLAYNODE_EXTERN_C_BEGIN +/** + Returns the appropriate interface state for a given ASDisplayNode and window + */ +extern ASInterfaceState ASInterfaceStateForDisplayNode(ASDisplayNode *displayNode, UIWindow *window); + /** Given a layer, returns the associated display node, if any. */ @@ -75,10 +80,10 @@ extern ASDisplayNode * _Nullable ASViewToDisplayNode(UIView * _Nullable view); extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node); /** - This function will walk the layer heirarchy, spanning discontinuous sections of the node heirarchy (e.g. the layers + This function will walk the layer hierarchy, spanning discontinuous sections of the node hierarchy (e.g. the layers of UIKit intermediate views in UIViewControllers, UITableView, UICollectionView). In the event that a node's backing layer is not created yet, the function will only walk the direct subnodes instead - of forcing the layer heirarchy to be created. + of forcing the layer hierarchy to be created. */ extern void ASDisplayNodePerformBlockOnEveryNode(CALayer * _Nullable layer, ASDisplayNode * _Nullable node, void(^block)(ASDisplayNode *node)); @@ -91,12 +96,12 @@ extern void ASDisplayNodePerformBlockOnEverySubnode(ASDisplayNode *node, void(^b /** Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block. */ -extern id _Nullable ASDisplayNodeFind(ASDisplayNode * _Nullable node, BOOL (^block)(ASDisplayNode *node)); +extern id _Nullable ASDisplayNodeFindFirstSupernode(ASDisplayNode * _Nullable node, BOOL (^block)(ASDisplayNode *node)); /** Given a display node, traverses up the layer tree hierarchy, returning the first display node of kind class. */ -extern id _Nullable ASDisplayNodeFindClass(ASDisplayNode *start, Class c); +extern id _Nullable ASDisplayNodeFindFirstSupernodeOfClass(ASDisplayNode *start, Class c); /** * Given two nodes, finds their most immediate common parent. Used for geometry conversion methods. @@ -109,7 +114,7 @@ extern id _Nullable ASDisplayNodeFindClass(ASDisplayNode *start, Class c); extern ASDisplayNode * _Nullable ASDisplayNodeFindClosestCommonAncestor(ASDisplayNode *node1, ASDisplayNode *node2); /** - Given a display node, collects all descendents. This is a specialization of ASCollectContainer() that walks the Core Animation layer tree as opposed to the display node tree, thus supporting non-continues display node hierarchies. + Given a display node, collects all descendants. This is a specialization of ASCollectContainer() that walks the Core Animation layer tree as opposed to the display node tree, thus supporting non-continues display node hierarchies. */ extern NSArray *ASCollectDisplayNodes(ASDisplayNode *node); @@ -124,7 +129,12 @@ extern NSArray *ASDisplayNodeFindAllSubnodes(ASDisplayNode *sta extern NSArray *ASDisplayNodeFindAllSubnodesOfClass(ASDisplayNode *start, Class c); /** - Given a display node, traverses down the node hierarchy, returning the depth-first display node that pass the block. + Given a display node, traverses down the node hierarchy, returning the depth-first display node, including the start node that pass the block. + */ +extern __kindof ASDisplayNode * ASDisplayNodeFindFirstNode(ASDisplayNode *start, BOOL (^block)(ASDisplayNode *node)); + +/** + Given a display node, traverses down the node hierarchy, returning the depth-first display node, excluding the start node, that pass the block */ extern __kindof ASDisplayNode * ASDisplayNodeFindFirstSubnode(ASDisplayNode *start, BOOL (^block)(ASDisplayNode *node)); diff --git a/AsyncDisplayKit/ASDisplayNodeExtras.mm b/AsyncDisplayKit/ASDisplayNodeExtras.mm index 67e9185d4e..dad6da1b70 100644 --- a/AsyncDisplayKit/ASDisplayNodeExtras.mm +++ b/AsyncDisplayKit/ASDisplayNodeExtras.mm @@ -10,6 +10,21 @@ #import "ASDisplayNodeInternal.h" #import "ASDisplayNode+FrameworkPrivate.h" +extern ASInterfaceState ASInterfaceStateForDisplayNode(ASDisplayNode *displayNode, UIWindow *window) +{ + ASDisplayNodeCAssert(![displayNode isLayerBacked], @"displayNode must not be layer backed as it may have a nil window"); + if (displayNode && [displayNode supportsRangeManagedInterfaceState]) { + // Directly clear the visible bit if we are not in a window. This means that the interface state is, + // if not already, about to be set to invisible as it is not possible for an element to be visible + // while outside of a window. + ASInterfaceState interfaceState = displayNode.interfaceState; + return (window == nil ? (interfaceState &= (~ASInterfaceStateVisible)) : interfaceState); + } else { + // For not range managed nodes we might be on our own to try to guess if we're visible. + return (window == nil ? ASInterfaceStateNone : (ASInterfaceStateVisible | ASInterfaceStateDisplay)); + } +} + extern ASDisplayNode *ASLayerToDisplayNode(CALayer *layer) { return layer.asyncdisplaykit_node; @@ -36,7 +51,9 @@ extern void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode * } if (layer) { - for (CALayer *sublayer in [layer sublayers]) { + /// NOTE: The docs say `sublayers` returns a copy, but it does not. + /// See: http://stackoverflow.com/questions/14854480/collection-calayerarray-0x1ed8faa0-was-mutated-while-being-enumerated + for (CALayer *sublayer in [[layer sublayers] copy]) { ASDisplayNodePerformBlockOnEveryNode(sublayer, nil, block); } } else if (node) { @@ -53,7 +70,7 @@ extern void ASDisplayNodePerformBlockOnEverySubnode(ASDisplayNode *node, void(^b } } -id ASDisplayNodeFind(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *node)) +id ASDisplayNodeFindFirstSupernode(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *node)) { CALayer *layer = node.layer; @@ -68,9 +85,9 @@ id ASDisplayNodeFind(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *node)) return nil; } -id ASDisplayNodeFindClass(ASDisplayNode *start, Class c) +id ASDisplayNodeFindFirstSupernodeOfClass(ASDisplayNode *start, Class c) { - return ASDisplayNodeFind(start, ^(ASDisplayNode *n) { + return ASDisplayNodeFindFirstSupernode(start, ^(ASDisplayNode *n) { return [n isKindOfClass:c]; }); } @@ -128,10 +145,10 @@ extern NSArray *ASDisplayNodeFindAllSubnodesOfClass(ASDisplayNo #pragma mark - Find first subnode -static ASDisplayNode *_ASDisplayNodeFindFirstSubnode(ASDisplayNode *startNode, BOOL includeStartNode, BOOL (^block)(ASDisplayNode *node)) +static ASDisplayNode *_ASDisplayNodeFindFirstNode(ASDisplayNode *startNode, BOOL includeStartNode, BOOL (^block)(ASDisplayNode *node)) { for (ASDisplayNode *subnode in startNode.subnodes) { - ASDisplayNode *foundNode = _ASDisplayNodeFindFirstSubnode(subnode, YES, block); + ASDisplayNode *foundNode = _ASDisplayNodeFindFirstNode(subnode, YES, block); if (foundNode) { return foundNode; } @@ -143,9 +160,14 @@ static ASDisplayNode *_ASDisplayNodeFindFirstSubnode(ASDisplayNode *startNode, B return nil; } +extern __kindof ASDisplayNode * ASDisplayNodeFindFirstNode(ASDisplayNode *startNode, BOOL (^block)(ASDisplayNode *node)) +{ + return _ASDisplayNodeFindFirstNode(startNode, YES, block); +} + extern __kindof ASDisplayNode * ASDisplayNodeFindFirstSubnode(ASDisplayNode *startNode, BOOL (^block)(ASDisplayNode *node)) { - return _ASDisplayNodeFindFirstSubnode(startNode, NO, block); + return _ASDisplayNodeFindFirstNode(startNode, NO, block); } extern __kindof ASDisplayNode * ASDisplayNodeFindFirstSubnodeOfClass(ASDisplayNode *start, Class c) @@ -155,9 +177,9 @@ extern __kindof ASDisplayNode * ASDisplayNodeFindFirstSubnodeOfClass(ASDisplayNo }); } -static inline BOOL _ASDisplayNodeIsAncestorOfDisplayNode(ASDisplayNode *possibleAncestor, ASDisplayNode *possibleDescendent) +static inline BOOL _ASDisplayNodeIsAncestorOfDisplayNode(ASDisplayNode *possibleAncestor, ASDisplayNode *possibleDescendant) { - ASDisplayNode *supernode = possibleDescendent; + ASDisplayNode *supernode = possibleDescendant; while (supernode) { if (supernode == possibleAncestor) { return YES; diff --git a/AsyncDisplayKit/ASEditableTextNode.h b/AsyncDisplayKit/ASEditableTextNode.h index 832611c094..22ba5822a0 100644 --- a/AsyncDisplayKit/ASEditableTextNode.h +++ b/AsyncDisplayKit/ASEditableTextNode.h @@ -7,6 +7,7 @@ */ #import +#import NS_ASSUME_NONNULL_BEGIN @@ -18,7 +19,25 @@ NS_ASSUME_NONNULL_BEGIN */ @interface ASEditableTextNode : ASDisplayNode -// @abstract The text node's delegate, which must conform to the protocol. +/** + * @abstract Initializes an editable text node using default TextKit components. + * + * @returns An initialized ASEditableTextNode. + */ +- (instancetype)init; + +/** + * @abstract Initializes an editable text node using the provided TextKit components. + * + * @param textKitComponents The TextKit stack used to render text. + * @param placeholderTextKitComponents The TextKit stack used to render placeholder text. + * + * @returns An initialized ASEditableTextNode. + */ +- (instancetype)initWithTextKitComponents:(ASTextKitComponents *)textKitComponents + placeholderTextKitComponents:(ASTextKitComponents *)placeholderTextKitComponents; + +//! @abstract The text node's delegate, which must conform to the protocol. @property (nonatomic, readwrite, weak) id delegate; #pragma mark - Configuration @@ -66,12 +85,12 @@ NS_ASSUME_NONNULL_BEGIN //! @abstract The text input mode used by the receiver's keyboard, if it is visible. This value is undefined if the receiver is not the first responder. @property (nonatomic, readonly) UITextInputMode *textInputMode; -/* +/** @abstract The textContainerInset of both the placeholder and typed textView. This value defaults to UIEdgeInsetsZero. */ @property (nonatomic, readwrite) UIEdgeInsets textContainerInset; -/* +/** @abstract The returnKeyType of the keyboard. This value defaults to UIReturnKeyDefault. */ @property (nonatomic, readwrite) UIReturnKeyType returnKeyType; @@ -129,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN @abstract Indicates to the delegate that the text node's selection has changed. @param editableTextNode An editable text node. @param fromSelectedRange The previously selected range. - @param toSelectedRange The current selected range. Equvialent to the property. + @param toSelectedRange The current selected range. Equivalent to the property. @param dueToEditing YES if the selection change was due to editing; NO otherwise. @discussion You can access the selection of the receiver via . */ diff --git a/AsyncDisplayKit/ASEditableTextNode.mm b/AsyncDisplayKit/ASEditableTextNode.mm index 486f0eef38..ba0b0b1f99 100644 --- a/AsyncDisplayKit/ASEditableTextNode.mm +++ b/AsyncDisplayKit/ASEditableTextNode.mm @@ -12,7 +12,6 @@ #import "ASDisplayNode+Subclasses.h" #import "ASEqualityHelpers.h" -#import "ASTextKitHelpers.h" #import "ASTextNodeWordKerner.h" #import "ASThread.h" @@ -45,6 +44,8 @@ - (void)setScrollEnabled:(BOOL)scrollEnabled { _shouldBlockPanGesture = !scrollEnabled; + self.scrollsToTop = scrollEnabled; + [super setScrollEnabled:YES]; } @@ -93,21 +94,29 @@ #pragma mark - NSObject Overrides - (instancetype)init +{ + return [self initWithTextKitComponents:[ASTextKitComponents componentsWithAttributedSeedString:nil textContainerSize:CGSizeZero] + placeholderTextKitComponents:[ASTextKitComponents componentsWithAttributedSeedString:nil textContainerSize:CGSizeZero]]; +} + +- (instancetype)initWithTextKitComponents:(ASTextKitComponents *)textKitComponents + placeholderTextKitComponents:(ASTextKitComponents *)placeholderTextKitComponents { if (!(self = [super init])) return nil; _displayingPlaceholder = YES; + _scrollEnabled = YES; // Create the scaffolding for the text view. - _textKitComponents = [ASTextKitComponents componentsWithAttributedSeedString:nil textContainerSize:CGSizeZero]; + _textKitComponents = textKitComponents; _textKitComponents.layoutManager.delegate = self; _wordKerner = [[ASTextNodeWordKerner alloc] init]; _returnKeyType = UIReturnKeyDefault; _textContainerInset = UIEdgeInsetsZero; // Create the placeholder scaffolding. - _placeholderTextKitComponents = [ASTextKitComponents componentsWithAttributedSeedString:nil textContainerSize:CGSizeZero]; + _placeholderTextKitComponents = placeholderTextKitComponents; _placeholderTextKitComponents.layoutManager.delegate = self; return self; @@ -161,7 +170,7 @@ // Create and configure our text view. _textKitComponents.textView = self.textView; - //_textKitComponents.textView = NO; // Unfortunately there's a bug here with iOS 7 DP5 that causes the text-view to only be one line high when scrollEnabled is NO. rdar://14729288 + _textKitComponents.textView.scrollEnabled = _scrollEnabled; _textKitComponents.textView.delegate = self; #if TARGET_OS_IOS _textKitComponents.textView.editable = YES; @@ -309,7 +318,7 @@ if (ASObjectIsEqual(_placeholderTextKitComponents.textStorage, attributedPlaceholderText)) return; - [_placeholderTextKitComponents.textStorage setAttributedString:attributedPlaceholderText ?: [[NSAttributedString alloc] initWithString:@""]]; + [_placeholderTextKitComponents.textStorage setAttributedString:attributedPlaceholderText ? : [[NSAttributedString alloc] initWithString:@""]]; _textKitComponents.textView.accessibilityHint = attributedPlaceholderText.string; } @@ -332,7 +341,7 @@ // If we (_cmd) are called while the text view itself is updating (-textViewDidUpdate:), you cannot update the text storage and expect perfect propagation to the text view. // Thus, we always update the textview directly if it's been created already. - if (ASObjectIsEqual((_textKitComponents.textView.attributedText ?: _textKitComponents.textStorage), attributedText)) + if (ASObjectIsEqual((_textKitComponents.textView.attributedText ? : _textKitComponents.textStorage), attributedText)) return; // If the cursor isn't at the end of the text, we need to preserve the selected range to avoid moving the cursor. diff --git a/AsyncDisplayKit/ASEqualityHashHelpers.mm b/AsyncDisplayKit/ASEqualityHashHelpers.mm index ca159fc980..decce0064c 100644 --- a/AsyncDisplayKit/ASEqualityHashHelpers.mm +++ b/AsyncDisplayKit/ASEqualityHashHelpers.mm @@ -10,11 +10,6 @@ #import "ASEqualityHashHelpers.h" -#import -#import -#import -#import - NSUInteger ASIntegerArrayHash(const NSUInteger *subhashes, NSUInteger count) { uint64_t result = subhashes[0]; diff --git a/AsyncDisplayKit/ASImageNode.h b/AsyncDisplayKit/ASImageNode.h index b2298752e5..8ce01b6397 100644 --- a/AsyncDisplayKit/ASImageNode.h +++ b/AsyncDisplayKit/ASImageNode.h @@ -33,7 +33,7 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); * the layer's contentsCenter property. Non-stretchable images work too, of * course. */ -@property (nullable, atomic, retain) UIImage *image; +@property (nullable, atomic, strong) UIImage *image; /** @abstract The placeholder color. @@ -94,7 +94,7 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); * @discussion Can be used to add image effects (such as rounding, adding * borders, or other pattern overlays) without extraneous display calls. */ -@property (nonatomic, readwrite, copy) asimagenode_modification_block_t imageModificationBlock; +@property (nullable, nonatomic, readwrite, copy) asimagenode_modification_block_t imageModificationBlock; /** * @abstract Marks the receiver as needing display and performs a block after diff --git a/AsyncDisplayKit/ASImageNode.mm b/AsyncDisplayKit/ASImageNode.mm index 94891a62ed..3ab12e565a 100644 --- a/AsyncDisplayKit/ASImageNode.mm +++ b/AsyncDisplayKit/ASImageNode.mm @@ -25,10 +25,11 @@ @interface _ASImageNodeDrawParameters : NSObject +@property (nonatomic, retain) UIImage *image; @property (nonatomic, assign) BOOL opaque; @property (nonatomic, assign) CGRect bounds; @property (nonatomic, assign) CGFloat contentsScale; -@property (nonatomic, retain) UIColor *backgroundColor; +@property (nonatomic, strong) UIColor *backgroundColor; @property (nonatomic, assign) UIViewContentMode contentMode; @end @@ -36,11 +37,17 @@ // TODO: eliminate explicit parameters with a set of keys copied from the node @implementation _ASImageNodeDrawParameters -- (id)initWithBounds:(CGRect)bounds opaque:(BOOL)opaque contentsScale:(CGFloat)contentsScale backgroundColor:(UIColor *)backgroundColor contentMode:(UIViewContentMode)contentMode +- (id)initWithImage:(UIImage *)image + bounds:(CGRect)bounds + opaque:(BOOL)opaque + contentsScale:(CGFloat)contentsScale + backgroundColor:(UIColor *)backgroundColor + contentMode:(UIViewContentMode)contentMode { - self = [self init]; - if (!self) return nil; + if (!(self = [self init])) + return nil; + _image = image; _opaque = opaque; _bounds = bounds; _contentsScale = contentsScale; @@ -93,12 +100,6 @@ _cropDisplayBounds = CGRectNull; _placeholderColor = ASDisplayNodeDefaultPlaceholderColor(); - if ([ASImageNode shouldShowImageScalingOverlay]) { - _debugLabelNode = [[ASTextNode alloc] init]; - _debugLabelNode.layerBacked = YES; - [self addSubnode:_debugLabelNode]; - } - return self; } @@ -133,8 +134,21 @@ _image = image; _imageLock.unlock(); + [self invalidateCalculatedLayout]; - [self setNeedsDisplay]; + if (image) { + [self setNeedsDisplay]; + + if ([ASImageNode shouldShowImageScalingOverlay]) { + ASPerformBlockOnMainThread(^{ + _debugLabelNode = [[ASTextNode alloc] init]; + _debugLabelNode.layerBacked = YES; + [self addSubnode:_debugLabelNode]; + }); + } + } else { + self.contents = nil; + } } else { _imageLock.unlock(); // We avoid using MutexUnlocker as it needlessly re-locks at the end of the scope. } @@ -156,11 +170,12 @@ - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer { - return [[_ASImageNodeDrawParameters alloc] initWithBounds:self.bounds - opaque:self.opaque - contentsScale:self.contentsScaleForDisplay - backgroundColor:self.backgroundColor - contentMode:self.contentMode]; + return [[_ASImageNodeDrawParameters alloc] initWithImage:self.image + bounds:self.bounds + opaque:self.opaque + contentsScale:self.contentsScaleForDisplay + backgroundColor:self.backgroundColor + contentMode:self.contentMode]; } - (NSDictionary *)debugLabelAttributes @@ -171,21 +186,26 @@ - (UIImage *)displayWithParameters:(_ASImageNodeDrawParameters *)parameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled { - UIImage *image; - BOOL cropEnabled; - BOOL forceUpscaling; - CGFloat contentsScale; - CGRect cropDisplayBounds; - CGRect cropRect; + UIImage *image = parameters.image; + if (!image) { + return nil; + } + + BOOL forceUpscaling = NO; + BOOL cropEnabled = NO; + BOOL isOpaque = parameters.opaque; + UIColor *backgroundColor = parameters.backgroundColor; + UIViewContentMode contentMode = parameters.contentMode; + CGFloat contentsScale = 0.0; + CGRect cropDisplayBounds = CGRectZero; + CGRect cropRect = CGRectZero; asimagenode_modification_block_t imageModificationBlock; { ASDN::MutexLocker l(_imageLock); - image = _image; - if (!image) { - return nil; - } + // FIXME: There is a small risk of these values changing between the main thread creation of drawParameters, and the execution of this method. + // We should package these up into the draw parameters object. Might be easiest to create a struct for the non-objects and make it one property. cropEnabled = _cropEnabled; forceUpscaling = _forceUpscaling; contentsScale = _contentsScaleForDisplay; @@ -194,16 +214,12 @@ imageModificationBlock = _imageModificationBlock; } + BOOL hasValidCropBounds = cropEnabled && !CGRectIsNull(cropDisplayBounds) && !CGRectIsEmpty(cropDisplayBounds); + CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : parameters.bounds); + ASDisplayNodeContextModifier preContextBlock = self.willDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier postContextBlock = self.didDisplayNodeContentWithRenderingContext; - BOOL hasValidCropBounds = cropEnabled && !CGRectIsNull(cropDisplayBounds) && !CGRectIsEmpty(cropDisplayBounds); - - CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : parameters.bounds); - BOOL isOpaque = parameters.opaque; - UIColor *backgroundColor = parameters.backgroundColor; - UIViewContentMode contentMode = parameters.contentMode; - ASDisplayNodeAssert(contentsScale > 0, @"invalid contentsScale at display time"); // if the image is resizable, bail early since the image has likely already been configured @@ -232,17 +248,15 @@ } } - BOOL contentModeSupported = contentMode == UIViewContentModeScaleAspectFill - || contentMode == UIViewContentModeScaleAspectFit - || contentMode == UIViewContentModeCenter; + BOOL contentModeSupported = contentMode == UIViewContentModeScaleAspectFill || + contentMode == UIViewContentModeScaleAspectFit || + contentMode == UIViewContentModeCenter; - CGSize backingSize; - CGRect imageDrawRect; + CGSize backingSize = CGSizeZero; + CGRect imageDrawRect = CGRectZero; - if (boundsSizeInPixels.width * contentsScale < 1.0f || - boundsSizeInPixels.height * contentsScale < 1.0f || - imageSizeInPixels.width < 1.0f || - imageSizeInPixels.height < 1.0f) { + if (boundsSizeInPixels.width * contentsScale < 1.0f || boundsSizeInPixels.height * contentsScale < 1.0f || + imageSizeInPixels.width < 1.0f || imageSizeInPixels.height < 1.0f) { return nil; } @@ -260,10 +274,8 @@ &imageDrawRect); } - if (backingSize.width <= 0.0f || - backingSize.height <= 0.0f || - imageDrawRect.size.width <= 0.0f || - imageDrawRect.size.height <= 0.0f) { + if (backingSize.width <= 0.0f || backingSize.height <= 0.0f || + imageDrawRect.size.width <= 0.0f || imageDrawRect.size.height <= 0.0f) { return nil; } diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index e7ec4cab2b..96a4536a69 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -134,12 +134,14 @@ - (void)setOptions:(MKMapSnapshotOptions *)options { ASDN::MutexLocker l(_propertyLock); - _options = options; - if (self.isLiveMap) { - [self applySnapshotOptions]; - } else { - [self resetSnapshotter]; - [self takeSnapshot]; + if (!_options || ![options isEqual:_options]) { + _options = options; + if (self.isLiveMap) { + [self applySnapshotOptions]; + } else if (_snapshotter) { + [self destroySnapshotter]; + [self takeSnapshot]; + } } } @@ -160,7 +162,11 @@ if (!_snapshotter) { [self setUpSnapshotter]; } - [_snapshotter cancel]; + + if (_snapshotter.isLoading) { + return; + } + [_snapshotter startWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionHandler:^(MKMapSnapshot *snapshot, NSError *error) { if (!error) { @@ -207,12 +213,10 @@ _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:self.options]; } -- (void)resetSnapshotter +- (void)destroySnapshotter { - // FIXME: The semantics of this method / name would suggest that we cancel + destroy the snapshotter, - // but not that we create a new one. We should probably only create the new one in -takeSnapshot or something. [_snapshotter cancel]; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:self.options]; + _snapshotter = nil; } - (void)applySnapshotOptions @@ -260,7 +264,7 @@ - (void)setAnnotations:(NSArray *)annotations { - annotations = [annotations copy] ?: @[]; + annotations = [annotations copy] ? : @[]; ASDN::MutexLocker l(_propertyLock); _annotations = annotations; @@ -273,11 +277,14 @@ } #pragma mark - Layout -- (void)setSnapshotSizeIfNeeded:(CGSize)snapshotSize +- (void)setSnapshotSizeWithReloadIfNeeded:(CGSize)snapshotSize { - if (!CGSizeEqualToSize(self.options.size, snapshotSize)) { + if (snapshotSize.height > 0 && snapshotSize.width > 0 && !CGSizeEqualToSize(self.options.size, snapshotSize)) { _options.size = snapshotSize; - [self resetSnapshotter]; + if (_snapshotter) { + [self destroySnapshotter]; + [self takeSnapshot]; + } } } @@ -287,11 +294,11 @@ if (CGSizeEqualToSize(size, CGSizeZero)) { size = constrainedSize; } - [self setSnapshotSizeIfNeeded:size]; + [self setSnapshotSizeWithReloadIfNeeded:size]; return constrainedSize; } -// Layout isn't usually needed in the box model, but since we are making use of MKMapView this is preferred. +// -layout isn't usually needed over -layoutSpecThatFits, but this way we can avoid a needless node wrapper for MKMapView. - (void)layout { [super layout]; @@ -300,10 +307,9 @@ } else { // If our bounds.size is different from our current snapshot size, then let's request a new image from MKMapSnapshotter. if (_needsMapReloadOnBoundsChange) { - [self setSnapshotSizeIfNeeded:self.bounds.size]; + [self setSnapshotSizeWithReloadIfNeeded:self.bounds.size]; // FIXME: Adding a check for FetchData here seems to cause intermittent map load failures, but shouldn't. // if (ASInterfaceStateIncludesFetchData(self.interfaceState)) { - [self takeSnapshot]; } } } diff --git a/AsyncDisplayKit/ASMultiplexImageNode.h b/AsyncDisplayKit/ASMultiplexImageNode.h index 5c02ed6048..73a74cbdeb 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.h +++ b/AsyncDisplayKit/ASMultiplexImageNode.h @@ -55,7 +55,7 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) { * @abstract ASMultiplexImageNode is an image node that can load and display multiple versions of an image. For * example, it can display a low-resolution version of an image while the high-resolution version is loading. * - * @discussion ASMultiplexImageNode begins loading images when its *imageIdentifiers; /** - * @abstract Notify the receiver SSAAthat its data source has new UIImages or NSURLs available for . + * @abstract Notify the receiver SSAA that its data source has new UIImages or NSURLs available for . * * @discussion If a higher-quality image than is currently displayed is now available, it will be loaded. */ diff --git a/AsyncDisplayKit/ASMultiplexImageNode.mm b/AsyncDisplayKit/ASMultiplexImageNode.mm index db67cc4a21..351ff9c7d9 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.mm +++ b/AsyncDisplayKit/ASMultiplexImageNode.mm @@ -250,7 +250,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent // Delegateify if (_delegateFlags.displayFinish) { - if ([NSThread isMainThread]) + if (ASDisplayNodeThreadIsMain()) [_delegate multiplexImageNodeDidFinishDisplay:self]; else { __weak __typeof__(self) weakSelf = self; @@ -265,6 +265,11 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent } } +- (BOOL)placeholderShouldPersist +{ + return (self.image == nil && self.imageIdentifiers.count > 0); +} + /* displayWillStart in ASNetworkImageNode has a very similar implementation. Changes here are likely necessary in ASNetworkImageNode as well. */ - (void)displayWillStart @@ -405,7 +410,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent // Delegateify. // Note that we're using the params here instead of self.image and _displayedImageIdentifier because those can change before the async block below executes. if (_delegateFlags.updatedImageDisplayFinish) { - if ([NSThread isMainThread]) + if (ASDisplayNodeThreadIsMain()) [_delegate multiplexImageNode:self didDisplayUpdatedImage:image withIdentifier:displayedImageIdentifier]; else { __weak __typeof__(self) weakSelf = self; @@ -700,7 +705,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent options.synchronous = YES; } - PHImageManager *imageManager = strongSelf.imageManager ?: PHImageManager.defaultManager; + PHImageManager *imageManager = strongSelf.imageManager ? : PHImageManager.defaultManager; [imageManager requestImageForAsset:imageAsset targetSize:request.targetSize contentMode:request.contentMode options:options resultHandler:^(UIImage *image, NSDictionary *info) { NSError *error = info[PHImageErrorKey]; diff --git a/AsyncDisplayKit/ASNetworkImageNode.h b/AsyncDisplayKit/ASNetworkImageNode.h index 79070aaccc..bb867f576c 100644 --- a/AsyncDisplayKit/ASNetworkImageNode.h +++ b/AsyncDisplayKit/ASNetworkImageNode.h @@ -69,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setURL:(nullable NSURL *)URL resetToDefault:(BOOL)reset; /** - * If is a local file, set this property to YES to take advantage of UIKit's image cacheing. Defaults to YES. + * If is a local file, set this property to YES to take advantage of UIKit's image caching. Defaults to YES. */ @property (nonatomic, assign, readwrite) BOOL shouldCacheImage; @@ -79,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - /** * The methods declared by the ASNetworkImageNodeDelegate protocol allow the adopting delegate to respond to - * notifications such as fininished decoding and downloading an image. + * notifications such as finished decoding and downloading an image. */ @protocol ASNetworkImageNodeDelegate diff --git a/AsyncDisplayKit/ASNetworkImageNode.mm b/AsyncDisplayKit/ASNetworkImageNode.mm index 5b5f97e793..f909de9f82 100755 --- a/AsyncDisplayKit/ASNetworkImageNode.mm +++ b/AsyncDisplayKit/ASNetworkImageNode.mm @@ -132,15 +132,22 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; - (void)setDefaultImage:(UIImage *)defaultImage { - ASDN::MutexLocker l(_lock); + _lock.lock(); if (ASObjectIsEqual(defaultImage, _defaultImage)) { + _lock.unlock(); return; } _defaultImage = defaultImage; if (!_imageLoaded) { - self.image = _defaultImage; + _lock.unlock(); + // Locking: it is important to release _lock before entering setImage:, as it needs to release the lock before -invalidateCalculatedLayout. + // If we continue to hold the lock here, it will still be locked until the next unlock() call, causing a possible deadlock with + // -[ASNetworkImageNode displayWillStart] (which is called on a different thread / main, at an unpredictable time due to ASMainRunloopQueue). + self.image = defaultImage; + } else { + _lock.unlock(); } } @@ -166,6 +173,12 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; return _delegate; } +- (BOOL)placeholderShouldPersist +{ + ASDN::MutexLocker l(_lock); + return (self.image == nil && _URL != nil); +} + /* displayWillStart in ASMultiplexImageNode has a very similar implementation. Changes here are likely necessary in ASMultiplexImageNode as well. */ - (void)displayWillStart @@ -327,6 +340,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; - (void)_lazilyLoadImageIfNecessary { + // FIXME: We should revisit locking in this method (e.g. to access the instance variables at the top, and holding lock while calling delegate) if (!_imageLoaded && _URL != nil && _downloadIdentifier == nil) { { ASDN::MutexLocker l(_lock); diff --git a/AsyncDisplayKit/ASPagerFlowLayout.m b/AsyncDisplayKit/ASPagerFlowLayout.m index 2118a394f9..dcb89a4008 100644 --- a/AsyncDisplayKit/ASPagerFlowLayout.m +++ b/AsyncDisplayKit/ASPagerFlowLayout.m @@ -34,7 +34,10 @@ - (CGPoint)_targetContentOffsetForItemAtIndexPath:(NSIndexPath *)indexPath proposedContentOffset:(CGPoint)proposedContentOffset { - UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:self.currentIndexPath]; + if ([self _dataSourceIsEmpty]) { + return proposedContentOffset; + } + UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; CGFloat xOffset = (self.collectionView.bounds.size.width - attributes.frame.size.width) / 2; return CGPointMake(attributes.frame.origin.x - xOffset, proposedContentOffset.y); } @@ -52,6 +55,11 @@ return nil; } +- (BOOL)_dataSourceIsEmpty +{ + return ([self.collectionView numberOfSections] == 0 || [self.collectionView numberOfItemsInSection:0] == 0); +} + - (CGRect)_visibleRect { CGRect visibleRect; @@ -60,4 +68,4 @@ return visibleRect; } -@end \ No newline at end of file +@end diff --git a/AsyncDisplayKit/ASRunLoopQueue.mm b/AsyncDisplayKit/ASRunLoopQueue.mm index 7de377feab..a18f7a8a70 100644 --- a/AsyncDisplayKit/ASRunLoopQueue.mm +++ b/AsyncDisplayKit/ASRunLoopQueue.mm @@ -9,13 +9,28 @@ #import "ASRunLoopQueue.h" #import "ASThread.h" +#import #import +#define ASRunLoopQueueLoggingEnabled 0 + +static void runLoopSourceCallback(void *info) { + // No-op +#if ASRunLoopQueueLoggingEnabled + NSLog(@"<%@> - Called runLoopSourceCallback", info); +#endif +} + @interface ASRunLoopQueue () { CFRunLoopRef _runLoop; CFRunLoopObserverRef _runLoopObserver; + CFRunLoopSourceRef _runLoopSource; std::deque _internalQueue; ASDN::RecursiveMutex _internalQueueLock; + +#if ASRunLoopQueueLoggingEnabled + NSTimer *_runloopQueueLoggingTimer; +#endif } @property (nonatomic, copy) void (^queueConsumer)(id dequeuedItem, BOOL isQueueDrained); @@ -36,12 +51,34 @@ }; _runLoopObserver = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, handlerBlock); CFRunLoopAddObserver(_runLoop, _runLoopObserver, kCFRunLoopCommonModes); + + // It is not guaranteed that the runloop will turn if it has no scheduled work, and this causes processing of + // the queue to stop. Attaching a custom loop source to the run loop and signal it if new work needs to be done + CFRunLoopSourceContext *runLoopSourceContext = (CFRunLoopSourceContext *)calloc(1, sizeof(CFRunLoopSourceContext)); + runLoopSourceContext->perform = runLoopSourceCallback; +#if ASRunLoopQueueLoggingEnabled + runLoopSourceContext->info = (__bridge void *)self; +#endif + _runLoopSource = CFRunLoopSourceCreate(NULL, 0, runLoopSourceContext); + CFRunLoopAddSource(runloop, _runLoopSource, kCFRunLoopCommonModes); + free(runLoopSourceContext); + +#if ASRunLoopQueueLoggingEnabled + _runloopQueueLoggingTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(checkRunLoop) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:_runloopQueueLoggingTimer forMode:NSRunLoopCommonModes]; +#endif } return self; } - (void)dealloc { + if (CFRunLoopContainsSource(_runLoop, _runLoopSource, kCFRunLoopCommonModes)) { + CFRunLoopRemoveSource(_runLoop, _runLoopSource, kCFRunLoopCommonModes); + } + CFRelease(_runLoopSource); + _runLoopSource = nil; + if (CFRunLoopObserverIsValid(_runLoopObserver)) { CFRunLoopObserverInvalidate(_runLoopObserver); } @@ -49,11 +86,17 @@ _runLoopObserver = nil; } +#if ASRunLoopQueueLoggingEnabled +- (void)checkRunLoop +{ + NSLog(@"<%@> - Jobs: %ld", self, _internalQueue.size()); +} +#endif + - (void)processQueue { std::deque itemsToProcess = std::deque(); BOOL isQueueDrained = NO; - CFAbsoluteTime timestamp = 0; { ASDN::MutexLocker l(_internalQueueLock); @@ -72,7 +115,6 @@ if (_internalQueue.empty()) { isQueueDrained = YES; - timestamp = CFAbsoluteTimeGetCurrent(); } } @@ -84,6 +126,12 @@ self.queueConsumer(itemsToProcess[i], isQueueDrained); } } + + // If the queue is not fully drained yet force another run loop to process next batch of items + if (!isQueueDrained) { + CFRunLoopSourceSignal(_runLoopSource); + CFRunLoopWakeUp(_runLoop); + } } - (void)enqueue:(id)object @@ -105,6 +153,9 @@ if (!foundObject) { _internalQueue.push_back(object); + + CFRunLoopSourceSignal(_runLoopSource); + CFRunLoopWakeUp(_runLoop); } } diff --git a/AsyncDisplayKit/ASTableView.h b/AsyncDisplayKit/ASTableView.h index 28b825403a..fe1ac2a193 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -81,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Tuning parameters for a range type in the specified mode. * - * @param rangeMode The range mode to get the runing parameters for. + * @param rangeMode The range mode to get the running parameters for. * @param rangeType The range type to get the tuning parameters for. * * @returns A tuning parameter value for the given range type in the given mode. @@ -92,10 +92,10 @@ NS_ASSUME_NONNULL_BEGIN - (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType; /** - * Set the tuning parameters for a range type in the specigied mode. + * Set the tuning parameters for a range type in the specified mode. * * @param tuningParameters The tuning parameters to store for a range type. - * @param rangeMode The range mode to set the runing parameters for. + * @param rangeMode The range mode to set the running parameters for. * @param rangeType The range type to set the tuning parameters for. * * @see ASLayoutRangeMode @@ -143,7 +143,7 @@ NS_ASSUME_NONNULL_BEGIN * Concludes a series of method calls that insert, delete, select, or reload rows and sections of the table view, with animation enabled and no completion block. * You call this method to bracket a series of method calls that begins with beginUpdates and that consists of operations * to insert, delete, select, and reload rows and sections of the table view. When you call endUpdates, ASTableView begins animating - * the operations simultaneously. This method is must be called from the main thread. It's important to remeber that the ASTableView will + * the operations simultaneously. This method is must be called from the main thread. It's important to remember that the ASTableView will * be processing the updates asynchronously after this call is completed. */ - (void)endUpdates; @@ -152,7 +152,7 @@ NS_ASSUME_NONNULL_BEGIN * Concludes a series of method calls that insert, delete, select, or reload rows and sections of the table view. * You call this method to bracket a series of method calls that begins with beginUpdates and that consists of operations * to insert, delete, select, and reload rows and sections of the table view. When you call endUpdates, ASTableView begins animating - * the operations simultaneously. This method is must be called from the main thread. It's important to remeber that the ASTableView will + * the operations simultaneously. This method is must be called from the main thread. It's important to remember that the ASTableView will * be processing the updates asynchronously after this call and are not guaranteed to be reflected in the ASTableView until * the completion block is executed. * @@ -351,7 +351,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Indicator to lock the data source for data fetching in async mode. - * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistence or exception + * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception * due to the data access in async mode. * * @param tableView The sender. @@ -360,7 +360,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Indicator to unlock the data source for data fetching in asyn mode. - * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistence or exception + * We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception * due to the data access in async mode. * * @param tableView The sender. diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 695b1e8d7e..d8d9037d36 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -13,12 +13,14 @@ #import "ASCellNode+Internal.h" #import "ASChangeSetDataController.h" #import "ASDelegateProxy.h" +#import "ASDisplayNodeExtras.h" #import "ASDisplayNode+Beta.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASInternalHelpers.h" #import "ASLayout.h" #import "ASLayoutController.h" #import "ASRangeController.h" +#import "ASRangeControllerUpdateRangeProtocol+Beta.h" #import "_ASDisplayLayer.h" #import @@ -118,13 +120,13 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } @property (atomic, assign) BOOL asyncDataSourceLocked; -@property (nonatomic, retain, readwrite) ASDataController *dataController; +@property (nonatomic, strong, readwrite) ASDataController *dataController; // Used only when ASTableView is created directly rather than through ASTableNode. // We create a node so that logic related to appearance, memory management, etc can be located there // for both the node-based and view-based version of the table. // This also permits sharing logic with ASCollectionNode, as the superclass is not UIKit-controlled. -@property (nonatomic, retain) ASTableNode *strongTableNode; +@property (nonatomic, strong) ASTableNode *strongTableNode; // Always set, whether ASCollectionView is created directly or via ASCollectionNode. @property (nonatomic, weak) ASTableNode *tableNode; @@ -493,7 +495,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } - (void)adjustContentOffsetWithNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths inserting:(BOOL)inserting { - // Maintain the users visible window when inserting or deleteing cells by adjusting the content offset for nodes + // Maintain the users visible window when inserting or deleting cells by adjusting the content offset for nodes // before the visible area. If in a begin/end updates block this will update _contentOffsetAdjustment, otherwise it will // update self.contentOffset directly. @@ -501,7 +503,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; CGFloat dir = (inserting) ? +1 : -1; CGFloat adjustment = 0; - NSIndexPath *top = _contentOffsetAdjustmentTopVisibleRow ?: self.indexPathsForVisibleRows.firstObject; + NSIndexPath *top = _contentOffsetAdjustmentTopVisibleRow ? : self.indexPathsForVisibleRows.firstObject; for (int index = 0; index < indexPaths.count; index++) { NSIndexPath *indexPath = indexPaths[index]; @@ -602,6 +604,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)scrollViewDidScroll:(UIScrollView *)scrollView { + // If a scroll happenes the current range mode needs to go to full + ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; + if (ASInterfaceStateIncludesVisible(interfaceState)) { + [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; + } + for (_ASTableViewCell *tableCell in _cellsForVisibilityUpdates) { [[tableCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged inScrollView:scrollView @@ -786,15 +794,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (ASInterfaceState)interfaceStateForRangeController:(ASRangeController *)rangeController { - ASTableNode *tableNode = self.tableNode; - if (tableNode) { - return self.tableNode.interfaceState; - } else { - // Until we can always create an associated ASTableNode without a retain cycle, - // we might be on our own to try to guess if we're visible. The node normally - // handles this even if it is the root / directly added to the view hierarchy. - return (self.window != nil ? ASInterfaceStateVisible : ASInterfaceStateNone); - } + return ASInterfaceStateForDisplayNode(self.tableNode, self.window); } #pragma mark - ASRangeControllerDelegate @@ -1068,9 +1068,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; if (!visible && node.inHierarchy) { [node __exitHierarchy]; } - - // Trigger updating interfaceState for cells in case ASTableView becomes visible or invisible - [_rangeController visibleNodeIndexPathsDidChangeWithScrollDirection:self.scrollDirection]; + + // Updating the visible node index paths only for not range managed nodes. Range managed nodes will get their + // their update in the layout pass + if (![node supportsRangeManagedInterfaceState]) { + [_rangeController visibleNodeIndexPathsDidChangeWithScrollDirection:self.scrollDirection]; + } } @end diff --git a/AsyncDisplayKit/ASTableViewInternal.h b/AsyncDisplayKit/ASTableViewInternal.h index c6e444dfda..3c1eb2f0c0 100644 --- a/AsyncDisplayKit/ASTableViewInternal.h +++ b/AsyncDisplayKit/ASTableViewInternal.h @@ -12,7 +12,7 @@ @interface ASTableView (Internal) -@property (nonatomic, retain, readonly) ASDataController *dataController; +@property (nonatomic, strong, readonly) ASDataController *dataController; @property (nonatomic, weak, readwrite) ASTableNode *tableNode; @property (nonatomic, strong, readonly) ASRangeController *rangeController; diff --git a/AsyncDisplayKit/ASTextNode+Beta.h b/AsyncDisplayKit/ASTextNode+Beta.h index 5cf43aa5ad..564f5d1917 100644 --- a/AsyncDisplayKit/ASTextNode+Beta.h +++ b/AsyncDisplayKit/ASTextNode+Beta.h @@ -6,6 +6,7 @@ // Copyright © 2016 Facebook. All rights reserved. // +NS_ASSUME_NONNULL_BEGIN @interface ASTextNode () @@ -13,18 +14,19 @@ @abstract An array of descending scale factors that will be applied to this text node to try to make it fit within its constrained size @default nil (no scaling) */ -@property (nonatomic, copy) NSArray *pointSizeScaleFactors; +@property (nullable, nonatomic, copy) NSArray *pointSizeScaleFactors; #pragma mark - ASTextKit Customization /** A block to provide a hook to provide a custom NSLayoutManager to the ASTextKitRenderer */ -@property (nonatomic, copy) NSLayoutManager * (^layoutManagerCreationBlock)(void); +@property (nullable, nonatomic, copy) NSLayoutManager * (^layoutManagerCreationBlock)(void); /** - A block to provide a hook to provide a NSTextStorage to the Text Kit's layout manager. + A block to provide a hook to provide a NSTextStorage to the TextKit's layout manager. */ -@property (nonatomic, copy) NSTextStorage * (^textStorageCreationBlock)(NSAttributedString *attributedString); +@property (nullable, nonatomic, copy) NSTextStorage * (^textStorageCreationBlock)(NSAttributedString *_Nullable attributedString); +@end -@end \ No newline at end of file +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index daa1a2aa20..8ec7a77a20 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -17,7 +17,7 @@ #import #import "ASTextKitCoreTextAdditions.h" -#import "ASTextKitHelpers.h" +#import "ASTextKitComponents.h" #import "ASTextKitFontSizeAdjuster.h" #import "ASTextKitRenderer.h" #import "ASTextKitRenderer+Positioning.h" @@ -364,6 +364,12 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; } _attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString); + + if (_attributedString.length > 0) { + CGFloat screenScale = ASScreenScale(); + self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + } // Sync the truncation string with attributes from the updated _attributedString // Without this, the size calculation of the text with truncation applied will @@ -380,12 +386,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; self.accessibilityLabel = _attributedString.string; - if (_attributedString.length == 0) { - // We're not an accessibility element by default if there is no string. - self.isAccessibilityElement = NO; - } else { - self.isAccessibilityElement = YES; - } + // We're an accessibility element by default if there is a string. + self.isAccessibilityElement = _attributedString.length != 0; } #pragma mark - Text Layout @@ -475,7 +477,6 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; // Final output vars __block id linkAttributeValue = nil; - __block NSString *linkAttributeName = nil; __block BOOL inTruncationMessage = NO; [renderer enumerateTextIndexesAtPosition:point usingBlock:^(NSUInteger characterIndex, CGRect glyphBoundingRect, BOOL *stop) { @@ -544,7 +545,6 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; // Set the values for the next iteration linkAttributeValue = value; - linkAttributeName = name; break; } @@ -633,7 +633,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeOut.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; - fadeOut.fromValue = possibleFadeIn.toValue ?: @(((CALayer *)weakHighlightLayer.presentationLayer).opacity); + fadeOut.fromValue = possibleFadeIn.toValue ? : @(((CALayer *)weakHighlightLayer.presentationLayer).opacity); fadeOut.toValue = @0.0; fadeOut.fillMode = kCAFillModeBoth; fadeOut.duration = ASTextNodeHighlightFadeOutDuration; diff --git a/AsyncDisplayKit/ASVideoNode.h b/AsyncDisplayKit/ASVideoNode.h index 4f3d7eea67..3a45b2f04c 100644 --- a/AsyncDisplayKit/ASVideoNode.h +++ b/AsyncDisplayKit/ASVideoNode.h @@ -6,13 +6,16 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import +@class AVAsset, AVPlayer, AVPlayerItem; @protocol ASVideoNodeDelegate; -// This is a relatively new component of AsyncDisplayKit. It has many useful features, but -// there is room for further expansion and optimization. Please report any issues or requests -// in an issue on GitHub: https://github.com/facebook/AsyncDisplayKit/issues +// IMPORTANT NOTES: +// 1. Applications using ASVideoNode must link AVFoundation! (this provides the AV* classes below) +// 2. This is a relatively new component of AsyncDisplayKit. It has many useful features, but +// there is room for further expansion and optimization. Please report any issues or requests +// in an issue on GitHub: https://github.com/facebook/AsyncDisplayKit/issues @interface ASVideoNode : ASControlNode @property (atomic, strong, readonly) AVAsset *asset; diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index d29430587a..94084d215b 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -406,6 +406,7 @@ { ASDN::MutexLocker l(_videoLock); + _player.muted = muted; _muted = muted; } diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index fc345706c3..54c34b5813 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -14,7 +14,7 @@ #import #import #import - +#import #import #import @@ -40,10 +40,12 @@ #import #import +#import #import #import #import #import +#import #import #import #import @@ -66,7 +68,6 @@ #import #import #import -#import #import #import #import @@ -74,5 +75,9 @@ #import #import #import +#import +#import #import + +#import diff --git a/AsyncDisplayKit/Details/ASAbstractLayoutController.mm b/AsyncDisplayKit/Details/ASAbstractLayoutController.mm index 3ed6ccc5c2..b7426bd1c5 100644 --- a/AsyncDisplayKit/Details/ASAbstractLayoutController.mm +++ b/AsyncDisplayKit/Details/ASAbstractLayoutController.mm @@ -33,24 +33,24 @@ extern BOOL ASRangeTuningParametersEqualToRangeTuningParameters(ASRangeTuningPar _tuningParameters = std::vector> (ASLayoutRangeModeCount, std::vector (ASLayoutRangeTypeCount)); + _tuningParameters[ASLayoutRangeModeFull][ASLayoutRangeTypeDisplay] = { + .leadingBufferScreenfuls = 1.0, + .trailingBufferScreenfuls = 0.5 + }; + _tuningParameters[ASLayoutRangeModeFull][ASLayoutRangeTypeFetchData] = { + .leadingBufferScreenfuls = 2.5, + .trailingBufferScreenfuls = 1.5 + }; + _tuningParameters[ASLayoutRangeModeMinimum][ASLayoutRangeTypeDisplay] = { .leadingBufferScreenfuls = 0.25, .trailingBufferScreenfuls = 0.25 }; _tuningParameters[ASLayoutRangeModeMinimum][ASLayoutRangeTypeFetchData] = { - .leadingBufferScreenfuls = 1, - .trailingBufferScreenfuls = 1 + .leadingBufferScreenfuls = 0.25, + .trailingBufferScreenfuls = 0.5 }; - _tuningParameters[ASLayoutRangeModeFull][ASLayoutRangeTypeDisplay] = { - .leadingBufferScreenfuls = 1.5, - .trailingBufferScreenfuls = 0.75 - }; - _tuningParameters[ASLayoutRangeModeFull][ASLayoutRangeTypeFetchData] = { - .leadingBufferScreenfuls = 3, - .trailingBufferScreenfuls = 2 - }; - _tuningParameters[ASLayoutRangeModeVisibleOnly][ASLayoutRangeTypeDisplay] = { .leadingBufferScreenfuls = 0, .trailingBufferScreenfuls = 0 diff --git a/AsyncDisplayKit/Details/ASBasicImageDownloader.mm b/AsyncDisplayKit/Details/ASBasicImageDownloader.mm index 73301919cc..1b546f1eaf 100644 --- a/AsyncDisplayKit/Details/ASBasicImageDownloader.mm +++ b/AsyncDisplayKit/Details/ASBasicImageDownloader.mm @@ -240,7 +240,7 @@ static const char *kContextKey = NSStringFromClass(ASBasicImageDownloaderContext dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // associate metadata with it NSMutableDictionary *callbackData = [NSMutableDictionary dictionary]; - callbackData[kASBasicImageDownloaderContextCallbackQueue] = callbackQueue ?: dispatch_get_main_queue(); + callbackData[kASBasicImageDownloaderContextCallbackQueue] = callbackQueue ? : dispatch_get_main_queue(); if (downloadProgressBlock) { callbackData[kASBasicImageDownloaderContextProgressBlock] = [downloadProgressBlock copy]; diff --git a/AsyncDisplayKit/Details/ASBatchContext.h b/AsyncDisplayKit/Details/ASBatchContext.h index 452582f9cf..dc1986a792 100644 --- a/AsyncDisplayKit/Details/ASBatchContext.h +++ b/AsyncDisplayKit/Details/ASBatchContext.h @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN @interface ASBatchContext : NSObject /** - * Retreive the state of the current batch process. + * Retrieve the state of the current batch process. * * @returns A boolean reflecting if the owner of the context object is fetching another batch. */ @@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)batchFetchingWasCancelled; /** - * Notify the context object that something has interupted the batch fetching process. + * Notify the context object that something has interrupted the batch fetching process. * * @discussion Call this method only when something has corrupted the batch fetching process. Calling this method should * be left to the owner of the batch process unless there is a specific purpose. diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h index b2ee2ae8a8..cd640c3e2a 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h @@ -6,8 +6,9 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#pragma once +#import #import @class ASCollectionView; diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m index 6168730878..3fe377f3a3 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m @@ -104,11 +104,7 @@ - (BOOL)layoutHasSupplementaryViewOfKind:(NSString *)kind inSection:(NSUInteger)section collectionView:(ASCollectionView *)collectionView { CGSize size = [self sizeForSupplementaryViewOfKind:kind inSection:section collectionView:collectionView]; - if ([self usedLayoutValueForSize:size] > 0) { - return YES; - } else { - return NO; - } + return [self usedLayoutValueForSize:size] > 0; } - (CGFloat)usedLayoutValueForSize:(CGSize)size diff --git a/AsyncDisplayKit/Details/ASDataController+Subclasses.h b/AsyncDisplayKit/Details/ASDataController+Subclasses.h index ee9a51d254..51b7548f50 100644 --- a/AsyncDisplayKit/Details/ASDataController+Subclasses.h +++ b/AsyncDisplayKit/Details/ASDataController+Subclasses.h @@ -6,8 +6,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#ifndef ASDataControllerSubclasses_Included -#define ASDataControllerSubclasses_Included +#pragma once @class ASIndexedNodeContext; @@ -39,7 +38,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray *nodes, NS */ - (void)batchLayoutNodesFromContexts:(NSArray *)contexts ofKind:(NSString *)kind completion:(ASDataControllerCompletionBlock)completionBlock; -/* +/** * Perform measurement and layout of loaded nodes on the main thread, skipping unloaded nodes. * * @discussion Once nodes have loaded their views, we can't layout in the background so this is a chance @@ -162,5 +161,3 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray *nodes, NS - (void)willMoveSection:(NSInteger)section toSection:(NSInteger)newSection; @end - -#endif diff --git a/AsyncDisplayKit/Details/ASDataController.h b/AsyncDisplayKit/Details/ASDataController.h index 5042c45de4..190119ed62 100644 --- a/AsyncDisplayKit/Details/ASDataController.h +++ b/AsyncDisplayKit/Details/ASDataController.h @@ -6,8 +6,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#ifndef ASDataController_Included -#define ASDataController_Included +#pragma once #import #import @@ -131,7 +130,7 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; * @discussion If enabled, we will fetch data through `dataController:nodeAtIndexPath:` and `dataController:rowsInSection:` in background thread. * Otherwise, the methods will be invoked synchronically in calling thread. Enabling data fetching in async mode could avoid blocking main thread * while allocating cell on main thread, which is frequently reported issue for handling large scale data. On another hand, the application code - * will take the responsibility to avoid data inconsistence. Specifically, we will lock the data source through `dataControllerLockDataSource`, + * will take the responsibility to avoid data inconsistency. Specifically, we will lock the data source through `dataControllerLockDataSource`, * and unlock it by `dataControllerUnlockDataSource` after the data fetching. The application should not update the data source while * the data source is locked. */ @@ -195,5 +194,3 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; @end NS_ASSUME_NONNULL_END - -#endif diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index c485144d46..e5ddc276d4 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -34,7 +34,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; @interface ASDataController () { NSMutableArray *_externalCompletedNodes; // Main thread only. External data access can immediately query this if available. NSMutableDictionary *_completedNodes; // Main thread only. External data access can immediately query this if _externalCompletedNodes is unavailable. - NSMutableDictionary *_editingNodes; // Modified on _editingTransactionQueue only. Updates propogated to _completedNodes. + NSMutableDictionary *_editingNodes; // Modified on _editingTransactionQueue only. Updates propagated to _completedNodes. ASMainSerialQueue *_mainSerialQueue; @@ -129,15 +129,10 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)layoutLoadedNodes:(NSArray *)nodes fromContexts:(NSArray *)contexts ofKind:(NSString *)kind { - NSAssert(NSThread.isMainThread, @"Main thread layout must be on the main thread."); + NSAssert(ASDisplayNodeThreadIsMain(), @"Layout of loaded nodes must happen on the main thread."); ASDisplayNodeAssertTrue(nodes.count == contexts.count); - [contexts enumerateObjectsUsingBlock:^(ASIndexedNodeContext *context, NSUInteger idx, __unused BOOL * stop) { - ASCellNode *node = nodes[idx]; - if (node.isNodeLoaded) { - [self _layoutNode:node withConstrainedSize:context.constrainedSize]; - } - }]; + [self _layoutNodes:nodes fromContexts:contexts inIndexesOfRange:NSMakeRange(0, nodes.count) ofKind:kind]; } /** @@ -160,9 +155,31 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } +/** + * Perform measurement and layout of loaded or unloaded nodes based if they will be layed out on main thread or not + */ +- (void)_layoutNodes:(NSArray *)nodes fromContexts:(NSArray *)contexts inIndexesOfRange:(NSRange)range ofKind:(NSString *)kind +{ + if (_dataSource == nil) { + return; + } + + // For any given layout pass that occurs, this method will be called at least twice, once on the main thread and + // the background, to result in complete coverage of both loaded and unloaded nodes + BOOL isMainThread = ASDisplayNodeThreadIsMain(); + for (NSUInteger k = range.location; k < NSMaxRange(range); k++) { + ASCellNode *node = nodes[k]; + // Only nodes that are loaded should be layout on the main thread + if (node.isNodeLoaded == isMainThread) { + ASIndexedNodeContext *context = contexts[k]; + [self _layoutNode:node withConstrainedSize:context.constrainedSize]; + } + } +} + - (void)_layoutNodesFromContexts:(NSArray *)contexts ofKind:(NSString *)kind completion:(ASDataControllerCompletionBlock)completionBlock { - if (!contexts.count) { + if (!contexts.count || _dataSource == nil) { return; } @@ -200,25 +217,30 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); - [self layoutLoadedNodes:subarray fromContexts:[contexts subarrayWithRange:NSMakeRange(j, batchCount)] ofKind:kind]; + + [self _layoutNodes:subarray + fromContexts:contexts + inIndexesOfRange:NSMakeRange(0, batchCount) + ofKind:kind]; + } else { allocationBlock(); [_mainSerialQueue performBlockOnMainThread:^{ - [self layoutLoadedNodes:subarray fromContexts:[contexts subarrayWithRange:NSMakeRange(j, batchCount)] ofKind:kind]; + [self _layoutNodes:subarray + fromContexts:contexts + inIndexesOfRange:NSMakeRange(0, batchCount) + ofKind:kind]; }]; } [allocatedNodes addObjectsFromArray:subarray]; dispatch_group_async(layoutGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - for (NSUInteger k = j; k < j + batchCount; k++) { - ASCellNode *node = allocatedNodes[k]; - // Only measure nodes whose views aren't loaded, since we're in the background. - // We should already have measured loaded nodes before we left the main thread, using layoutLoadedNodes:ofKind:atIndexPaths: - if (!node.isNodeLoaded) { - [self _layoutNode:node withConstrainedSize:contexts[k].constrainedSize]; - } - } + // We should already have measured loaded nodes before we left the main thread. Layout the remaining once on a background thread. + [self _layoutNodes:allocatedNodes + fromContexts:contexts + inIndexesOfRange:NSMakeRange(j, batchCount) + ofKind:kind]; }); } @@ -244,7 +266,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(ASDataControllerCompletionBlock)completionBlock { - if (indexPaths.count == 0) { + if (!indexPaths.count || _dataSource == nil) { return; } @@ -265,7 +287,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(ASDataControllerCompletionBlock)completionBlock { - if (indexPaths.count == 0) { + if (!indexPaths.count || _dataSource == nil) { return; } @@ -285,8 +307,9 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)insertSections:(NSMutableArray *)sections ofKind:(NSString *)kind atIndexSet:(NSIndexSet *)indexSet completion:(void (^)(NSArray *sections, NSIndexSet *indexSet))completionBlock { - if (indexSet.count == 0) + if (!indexSet.count|| _dataSource == nil) { return; + } if (_editingNodes[kind] == nil) { _editingNodes[kind] = [NSMutableArray array]; @@ -307,8 +330,10 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)deleteSectionsOfKind:(NSString *)kind atIndexSet:(NSIndexSet *)indexSet completion:(void (^)(NSIndexSet *indexSet))completionBlock { - if (indexSet.count == 0) + if (!indexSet.count || _dataSource == nil) { return; + } + [_editingNodes[kind] removeObjectsAtIndexes:indexSet]; [_mainSerialQueue performBlockOnMainThread:^{ [_completedNodes[kind] removeObjectsAtIndexes:indexSet]; @@ -328,9 +353,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; */ - (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - if (indexPaths.count == 0) { - return; - } [self insertNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) { if (_delegateDidInsertNodes) [_delegate dataController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; @@ -345,9 +367,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; */ - (void)_deleteNodesAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - if (indexPaths.count == 0) { - return; - } [self deleteNodesOfKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) { if (_delegateDidDeleteNodes) [_delegate dataController:self didDeleteNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; @@ -355,7 +374,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; } /** - * Inserts sections, represented as arrays, into the backing store at the given indicies and notifies the delegate. + * Inserts sections, represented as arrays, into the backing store at the given indices and notifies the delegate. * * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted * in the completed store on the main thread. The delegate is invoked on the main thread. @@ -369,7 +388,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; } /** - * Removes sections at the given indicies from the backing store and notifies the delegate. + * Removes sections at the given indices from the backing store and notifies the delegate. * * @discussion Section array are first removed from the editing store, then the associated section in the completed * store is removed on the main thread. The delegate is invoked on the main thread. @@ -876,12 +895,12 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; [_editingTransactionQueue addOperationWithBlock:^{ LOG(@"Edit Transaction - moveRow: %@ > %@", indexPath, newIndexPath); - NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_editingNodes[ASDataControllerRowNodeKind], [NSArray arrayWithObject:indexPath]); - NSArray *indexPaths = [NSArray arrayWithObject:indexPath]; + NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_editingNodes[ASDataControllerRowNodeKind], @[indexPath]); + NSArray *indexPaths = @[indexPath]; [self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; // Don't re-calculate size for moving - NSArray *newIndexPaths = [NSArray arrayWithObject:newIndexPath]; + NSArray *newIndexPaths = @[newIndexPath]; [self _insertNodes:nodes atIndexPaths:newIndexPaths withAnimationOptions:animationOptions]; }]; }]; @@ -967,7 +986,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (NSArray *)completedNodes { ASDisplayNodeAssertMainThread(); - return _externalCompletedNodes != nil ? _externalCompletedNodes : _completedNodes[ASDataControllerRowNodeKind]; + return _externalCompletedNodes ? : _completedNodes[ASDataControllerRowNodeKind]; } #pragma mark - Dealloc diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h new file mode 100644 index 0000000000..6a42f18cbf --- /dev/null +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import "ASDimension.h" +#import "ASStackLayoutDefines.h" +#import "ASRelativeSize.h" + + +ASDISPLAYNODE_EXTERN_C_BEGIN +NS_ASSUME_NONNULL_BEGIN + +static const int kMaxEnvironmentStateBoolExtensions = 1; +static const int kMaxEnvironmentStateIntegerExtensions = 4; +static const int kMaxEnvironmentStateEdgeInsetExtensions = 1; + +#pragma mark - + +typedef struct ASEnvironmentStateExtensions { + // Values to store extensions + BOOL boolExtensions[kMaxEnvironmentStateBoolExtensions]; + NSInteger integerExtensions[kMaxEnvironmentStateIntegerExtensions]; + UIEdgeInsets edgeInsetsExtensions[kMaxEnvironmentStateEdgeInsetExtensions]; +} ASEnvironmentStateExtensions; + +#pragma mark - ASEnvironmentLayoutOptionsState + +typedef struct ASEnvironmentLayoutOptionsState { + CGFloat spacingBefore;// = 0; + CGFloat spacingAfter;// = 0; + BOOL flexGrow;// = NO; + BOOL flexShrink;// = NO; + ASRelativeDimension flexBasis;// = ASRelativeDimensionUnconstrained; + ASStackLayoutAlignSelf alignSelf;// = ASStackLayoutAlignSelfAuto; + CGFloat ascender;// = 0; + CGFloat descender;// = 0; + + ASRelativeSizeRange sizeRange;// = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero));; + CGPoint layoutPosition;// = CGPointZero; + + struct ASEnvironmentStateExtensions _extensions; +} ASEnvironmentLayoutOptionsState; + + +#pragma mark - ASEnvironmentHierarchyState + +typedef struct ASEnvironmentHierarchyState { + unsigned rasterized:1; // = NO + unsigned rangeManaged:1; // = NO + unsigned transitioningSupernodes:1; // = NO + unsigned layoutPending:1; // = NO +} ASEnvironmentHierarchyState; + + +#pragma mark - ASEnvironmentState + +typedef struct ASEnvironmentState { + struct ASEnvironmentHierarchyState hierarchyState; + struct ASEnvironmentLayoutOptionsState layoutOptionsState; +} ASEnvironmentState; +extern ASEnvironmentState ASEnvironmentStateMakeDefault(); + +ASDISPLAYNODE_EXTERN_C_END + + +#pragma mark - ASEnvironment + +/** + * ASEnvironment allows objects that conform to the ASEnvironment protocol to be able to propagate specific States + * defined in an ASEnvironmentState up and down the ASEnvironment tree. To be able to define how merges of + * States should happen, specific merge functions can be provided + */ +@protocol ASEnvironment + +/// The environment collection of an object which class conforms to the ASEnvironment protocol +- (ASEnvironmentState)environmentState; +- (void)setEnvironmentState:(ASEnvironmentState)environmentState; + +/// Returns the parent of an object which class conforms to the ASEnvironment protocol +- (id _Nullable)parent; + +/// Returns all children of an object which class conforms to the ASEnvironment protocol +- (NSArray> *)children; + +/// Classes should implement this method and return YES / NO dependent if upward propagation is enabled or not +- (BOOL)supportsUpwardPropagation; + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m new file mode 100644 index 0000000000..f3b2039f8f --- /dev/null +++ b/AsyncDisplayKit/Details/ASEnvironment.m @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironment.h" + +ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateMakeDefault() +{ + return (ASEnvironmentLayoutOptionsState) { + // Default values can be defined in here + }; +} + +ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() +{ + return (ASEnvironmentHierarchyState) { + // Default values can be defined in here + }; +} + +ASEnvironmentState ASEnvironmentStateMakeDefault() +{ + return (ASEnvironmentState) { + .layoutOptionsState = _ASEnvironmentLayoutOptionsStateMakeDefault(), + .hierarchyState = _ASEnvironmentHierarchyStateMakeDefault() + }; +} \ No newline at end of file diff --git a/AsyncDisplayKit/Details/ASMainSerialQueue.mm b/AsyncDisplayKit/Details/ASMainSerialQueue.mm index 10fb29107e..3112757af0 100644 --- a/AsyncDisplayKit/Details/ASMainSerialQueue.mm +++ b/AsyncDisplayKit/Details/ASMainSerialQueue.mm @@ -9,6 +9,7 @@ #import "ASMainSerialQueue.h" #import "ASThread.h" +#import "ASInternalHelpers.h" @interface ASMainSerialQueue () { @@ -45,7 +46,7 @@ ASDN::MutexLocker l(_serialQueueLock); dispatch_block_t block; if (_blocks.count > 0) { - block = [_blocks objectAtIndex:0]; + block = _blocks[0]; [_blocks removeObjectAtIndex:0]; } else { break; @@ -55,13 +56,7 @@ } while (true); }; - if ([NSThread isMainThread]) { - mainThread(); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - mainThread(); - }); - } + ASPerformBlockOnMainThread(mainThread); } - (NSString *)description diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index d89d117af4..7935564a3d 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -47,7 +47,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; _currentRangeMode = ASLayoutRangeModeInvalid; _didUpdateCurrentRange = NO; - [[self.class allRangeControllersWeakSet] addObject:self]; + [[[self class] allRangeControllersWeakSet] addObject:self]; return self; } @@ -59,13 +59,18 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; } } -#pragma mark - Core visible node range managment API +#pragma mark - Core visible node range management API + ++ (BOOL)isFirstRangeUpdateForRangeMode:(ASLayoutRangeMode)rangeMode +{ + return (rangeMode == ASLayoutRangeModeInvalid); +} + (ASLayoutRangeMode)rangeModeForInterfaceState:(ASInterfaceState)interfaceState currentRangeMode:(ASLayoutRangeMode)currentRangeMode { BOOL isVisible = (ASInterfaceStateIncludesVisible(interfaceState)); - BOOL isFirstRangeUpdate = (currentRangeMode == ASLayoutRangeModeInvalid); + BOOL isFirstRangeUpdate = [self isFirstRangeUpdateForRangeMode:currentRangeMode]; if (!isVisible || isFirstRangeUpdate) { return ASLayoutRangeModeMinimum; } @@ -184,7 +189,9 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; ASInterfaceState selfInterfaceState = [self interfaceState]; ASLayoutRangeMode rangeMode = _currentRangeMode; - if (!_didUpdateCurrentRange) { + // If the range mode is explicitly set via updateCurrentRangeWithMode: it will last in that mode until the + // range controller becomes visible again or explicitly changes the range mode again + if ((!_didUpdateCurrentRange && ASInterfaceStateIncludesVisible(selfInterfaceState)) || [[self class] isFirstRangeUpdateForRangeMode:rangeMode]) { rangeMode = [ASRangeController rangeModeForInterfaceState:selfInterfaceState currentRangeMode:_currentRangeMode]; } @@ -230,7 +237,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; _didUpdateCurrentRange = NO; if (!_rangeIsValid) { - [allIndexPaths addObjectsFromArray:ASIndexPathsForMultidimensionalArray(allNodes)]; + [allIndexPaths addObjectsFromArray:ASIndexPathsForTwoDimensionalArray(allNodes)]; } // TODO Don't register for notifications if this range update doesn't cause any node to enter rendering pipeline. @@ -286,13 +293,13 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; if (section != currentSectionIndex) { // Often we'll be dealing with indexPaths in the same section, but the set isn't sorted and we may even bounce // between the same ones. Still, this saves dozens of method calls to access the inner array and count. - currentSectionNodes = [allNodes objectAtIndex:section]; + currentSectionNodes = allNodes[section]; numberOfNodesInSection = [currentSectionNodes count]; currentSectionIndex = section; } if (row < numberOfNodesInSection) { - ASDisplayNode *node = [currentSectionNodes objectAtIndex:row]; + ASDisplayNode *node = currentSectionNodes[row]; ASDisplayNodeAssert(node.hierarchyState & ASHierarchyStateRangeManaged, @"All nodes reaching this point should be range-managed, or interfaceState may be incorrectly reset."); // Skip the many method calls of the recursive operation if the top level cell node already has the right interfaceState. @@ -345,7 +352,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; - (void)scheduledNodesDidDisplay:(NSNotification *)notification { - CFAbsoluteTime notificationTimestamp = ((NSNumber *)[notification.userInfo objectForKey:ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp]).doubleValue; + CFAbsoluteTime notificationTimestamp = ((NSNumber *) notification.userInfo[ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp]).doubleValue; if (_pendingDisplayNodesTimestamp < notificationTimestamp) { // The rendering engine has processed all the nodes this range controller scheduled. Let's schedule a range update [[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil]; diff --git a/AsyncDisplayKit/Details/ASRangeControllerUpdateRangeProtocol+Beta.h b/AsyncDisplayKit/Details/ASRangeControllerUpdateRangeProtocol+Beta.h index 1a36e57662..4f34cd1cef 100644 --- a/AsyncDisplayKit/Details/ASRangeControllerUpdateRangeProtocol+Beta.h +++ b/AsyncDisplayKit/Details/ASRangeControllerUpdateRangeProtocol+Beta.h @@ -34,7 +34,19 @@ @interface ASRangeController (ASRangeControllerUpdateRangeProtocol) -/// This is a way for a one way update of range with a given mode. +/** + * Update the range mode for a range controller to a explicitly set mode until the node that contains the range + * controller becomes visible again + * + * Logic for the automatic range mode: + * 1. If there are no visible node paths available nothing is to be done and no range update will happen + * 2. The initial range update if the range controller is visible always will be ASLayoutRangeModeCount + * (ASLayoutRangeModeMinimum) as it's the initial fetch + * 3. The range mode set explicitly via updateCurrentRangeWithMode: will last at least one range update. After that it + the range controller will use the explicit set range mode until it becomes visible and a new range update was + triggered or a new range mode via updateCurrentRangeWithMode: is set + * 4. If range mode is not explicitly set the range mode is variying based if the range controller is visible or not + */ - (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode; @end @@ -52,7 +64,7 @@ @interface ASViewController (ASRangeControllerUpdateRangeProtocol) -/// Automatically adjust range mode based on view evenets if the containing node confirms to the ASRangeControllerUpdateRangeProtocol +/// Automatically adjust range mode based on view events if the containing node confirms to the ASRangeControllerUpdateRangeProtocol @property (nonatomic, assign) BOOL automaticallyAdjustRangeModeBasedOnViewEvents; @end diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h index f169d4e50f..aa28f11f10 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h @@ -167,7 +167,7 @@ extern NSInteger const ASDefaultTransactionPriority; /** @summary Cancels all operations in the transaction. - @desc You can only cancel a commmitted transaction. + @desc You can only cancel a committed transaction. All completion blocks are always called, regardless of cancelation. Execution blocks may be skipped if canceled. */ diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm index 66a4fb0df9..be689c624f 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm @@ -18,7 +18,7 @@ NSInteger const ASDefaultTransactionPriority = 0; @interface ASDisplayNodeAsyncTransactionOperation : NSObject - (id)initWithOperationCompletionBlock:(asyncdisplaykit_async_transaction_operation_completion_block_t)operationCompletionBlock; @property (nonatomic, copy) asyncdisplaykit_async_transaction_operation_completion_block_t operationCompletionBlock; -@property (atomic, retain) id value; // set on bg queue by the operation block +@property (atomic, strong) id value; // set on bg queue by the operation block @end @implementation ASDisplayNodeAsyncTransactionOperation @@ -236,7 +236,7 @@ void ASAsyncTransactionQueue::GroupImpl::schedule(NSInteger priority, dispatch_q operation._block(); } operation._group->leave(); - operation._block = 0; // the block must be freed while mutex is unlocked + operation._block = nil; // the block must be freed while mutex is unlocked } } --entry._threadCount; @@ -484,7 +484,7 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() ASDisplayNodeAssert(_state != ASAsyncTransactionStateOpen, @"Transaction should not be open after committing group"); } // If we needed to commit the group above, -completeTransaction may have already been run. - // It is designed to accomodate this by checking _state to ensure it is not complete. + // It is designed to accommodate this by checking _state to ensure it is not complete. [self completeTransaction]; } } diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h index 32421c2543..690ce93cd6 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h @@ -10,8 +10,8 @@ @interface CALayer (ASAsyncTransactionContainerTransactions) -@property (nonatomic, retain, setter=asyncdisplaykit_setAsyncLayerTransactions:) NSHashTable *asyncdisplaykit_asyncLayerTransactions; -@property (nonatomic, retain, setter=asyncdisplaykit_setCurrentAsyncLayerTransaction:) _ASAsyncTransaction *asyncdisplaykit_currentAsyncLayerTransaction; +@property (nonatomic, strong, setter=asyncdisplaykit_setAsyncLayerTransactions:) NSHashTable *asyncdisplaykit_asyncLayerTransactions; +@property (nonatomic, strong, setter=asyncdisplaykit_setCurrentAsyncLayerTransaction:) _ASAsyncTransaction *asyncdisplaykit_currentAsyncLayerTransaction; - (void)asyncdisplaykit_asyncTransactionContainerWillBeginTransaction:(_ASAsyncTransaction *)transaction; - (void)asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:(_ASAsyncTransaction *)transaction; diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h index 628d461a39..9626418804 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h @@ -59,13 +59,13 @@ typedef NS_ENUM(NSUInteger, ASAsyncTransactionContainerState) { did not already exist. This method will always return an open, uncommitted transaction. @desc asyncdisplaykit_isAsyncTransactionContainer does not need to be YES for this to return a transaction. */ -@property (nonatomic, readonly, retain) _ASAsyncTransaction *asyncdisplaykit_asyncTransaction; +@property (nonatomic, readonly, strong) _ASAsyncTransaction *asyncdisplaykit_asyncTransaction; /** @summary Goes up the superlayer chain until it finds the first layer with asyncdisplaykit_isAsyncTransactionContainer=YES (including the receiver) and returns it. Returns nil if no parent container is found. */ -@property (nonatomic, readonly, retain) CALayer *asyncdisplaykit_parentTransactionContainer; +@property (nonatomic, readonly, strong) CALayer *asyncdisplaykit_parentTransactionContainer; @end @interface UIView (ASDisplayNodeAsyncTransactionContainer) diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h index c7b3da3217..198cf3a7f6 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h @@ -18,7 +18,7 @@ + (void)commit; /// Add a transaction container to be committed. -/// @param containerLayer A layer containing a transaction to be commited. May or may not be a container layer. +/// @param containerLayer A layer containing a transaction to be committed. May or may not be a container layer. /// @see ASAsyncTransactionContainer - (void)addTransactionContainer:(CALayer *)containerLayer; @end diff --git a/AsyncDisplayKit/Details/UIView+ASConvenience.h b/AsyncDisplayKit/Details/UIView+ASConvenience.h index d84f79923f..b10e8900b1 100644 --- a/AsyncDisplayKit/Details/UIView+ASConvenience.h +++ b/AsyncDisplayKit/Details/UIView+ASConvenience.h @@ -20,20 +20,20 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) CGPoint position; @property (nonatomic, assign) CGFloat zPosition; @property (nonatomic, assign) CGPoint anchorPoint; -@property (nullable, nonatomic, retain) id contents; +@property (nullable, nonatomic, strong) id contents; @property (nonatomic, assign) CGFloat cornerRadius; @property (nonatomic, assign) CGFloat contentsScale; @property (nonatomic, assign) CATransform3D transform; @property (nonatomic, assign) CATransform3D sublayerTransform; @property (nonatomic, assign) BOOL needsDisplayOnBoundsChange; -@property (nonatomic, retain) __attribute__((NSObject)) CGColorRef shadowColor; +@property (nonatomic, strong) __attribute__((NSObject)) CGColorRef shadowColor; @property (nonatomic, assign) CGFloat shadowOpacity; @property (nonatomic, assign) CGSize shadowOffset; @property (nonatomic, assign) CGFloat shadowRadius; @property (nonatomic, assign) CGFloat borderWidth; @property (nonatomic, assign, getter = isOpaque) BOOL opaque; -@property (nonatomic, retain) __attribute__((NSObject)) CGColorRef borderColor; -@property (nonatomic, retain) __attribute__((NSObject)) CGColorRef backgroundColor; +@property (nonatomic, strong) __attribute__((NSObject)) CGColorRef borderColor; +@property (nonatomic, strong) __attribute__((NSObject)) CGColorRef backgroundColor; @property (nonatomic, assign) BOOL allowsEdgeAntialiasing; @property (nonatomic, assign) unsigned int edgeAntialiasingMask; @@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, getter=isHidden) BOOL hidden; @property (nonatomic, assign) BOOL autoresizesSubviews; @property (nonatomic, assign) UIViewAutoresizing autoresizingMask; -@property (nonatomic, retain, null_resettable) UIColor *tintColor; +@property (nonatomic, strong, null_resettable) UIColor *tintColor; @property (nonatomic, assign) CGFloat alpha; @property (nonatomic, assign) CGRect bounds; @property (nonatomic, assign) CGRect frame; // Only for use with nodes wrapping synchronous views @@ -71,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN @property (atomic, copy) NSString *accessibilityValue; @property (atomic, assign) UIAccessibilityTraits accessibilityTraits; @property (atomic, assign) CGRect accessibilityFrame; - @property (atomic, retain) NSString *accessibilityLanguage; + @property (atomic, strong) NSString *accessibilityLanguage; @property (atomic, assign) BOOL accessibilityElementsHidden; @property (atomic, assign) BOOL accessibilityViewIsModal; @property (atomic, assign) BOOL shouldGroupAccessibilityChildren; diff --git a/AsyncDisplayKit/Details/_ASDisplayView.mm b/AsyncDisplayKit/Details/_ASDisplayView.mm index 1c117928e2..f4d95b99b8 100644 --- a/AsyncDisplayKit/Details/_ASDisplayView.mm +++ b/AsyncDisplayKit/Details/_ASDisplayView.mm @@ -23,7 +23,7 @@ // Keep the node alive while its view is active. If you create a view, add its layer to a layer hierarchy, then release // the view, the layer retains the view to prevent a crash. This replicates this behaviour for the node abstraction. -@property (nonatomic, retain, readwrite) ASDisplayNode *keepalive_node; +@property (nonatomic, strong, readwrite) ASDisplayNode *keepalive_node; @end @implementation _ASDisplayView @@ -90,6 +90,11 @@ self.keepalive_node = _node; } else if (currentSuperview && !newSuperview) { + // Clearing keepalive_node may cause deallocation of the node. In this case, __exitHierarchy may not have an opportunity (e.g. _node will be cleared + // by the time -didMoveToWindow occurs after this) to clear the Visible interfaceState, which we need to do before deallocation to meet an API guarantee. + if (_node.inHierarchy) { + [_node __exitHierarchy]; + } self.keepalive_node = nil; } diff --git a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h index f8413d275e..75a48443b7 100644 --- a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.h @@ -8,7 +8,7 @@ * */ -#import +#import /** How the child is centered within the spec. */ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecCenteringOptions) { @@ -25,19 +25,22 @@ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecCenteringOptions) { /** How much space the spec will take up. */ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecSizingOptions) { /** The spec will take up the maximum size possible */ - ASCenterLayoutSpecSizingOptionDefault, + ASCenterLayoutSpecSizingOptionDefault = ASRelativeLayoutSpecSizingOptionDefault, /** The spec will take up the minimum size possible along the X axis */ - ASCenterLayoutSpecSizingOptionMinimumX = 1 << 0, + ASCenterLayoutSpecSizingOptionMinimumX = ASRelativeLayoutSpecSizingOptionMinimumWidth, /** The spec will take up the minimum size possible along the Y axis */ - ASCenterLayoutSpecSizingOptionMinimumY = 1 << 1, + ASCenterLayoutSpecSizingOptionMinimumY = ASRelativeLayoutSpecSizingOptionMinimumHeight, /** Convenience option to take up the minimum size along both the X and Y axis */ - ASCenterLayoutSpecSizingOptionMinimumXY = ASCenterLayoutSpecSizingOptionMinimumX | ASCenterLayoutSpecSizingOptionMinimumY, + ASCenterLayoutSpecSizingOptionMinimumXY = ASRelativeLayoutSpecSizingOptionMinimumSize }; NS_ASSUME_NONNULL_BEGIN -/** Lays out a single layoutable child and position it so that it is centered into the layout bounds. */ -@interface ASCenterLayoutSpec : ASLayoutSpec +/** Lays out a single layoutable child and position it so that it is centered into the layout bounds. + * NOTE: ASRelativeLayoutSpec offers all of the capabilities of Center, and more. + * Check it out if you would like to be able to position the child at any corner or the middle of an edge. + */ +@interface ASCenterLayoutSpec : ASRelativeLayoutSpec @property (nonatomic, assign) ASCenterLayoutSpecCenteringOptions centeringOptions; @property (nonatomic, assign) ASCenterLayoutSpecSizingOptions sizingOptions; diff --git a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm index 5e81e1f3d2..147142db1c 100644 --- a/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASCenterLayoutSpec.mm @@ -23,13 +23,14 @@ sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions child:(id)child; { - if (!(self = [super init])) { + ASRelativeLayoutSpecPosition verticalPosition = [self verticalPositionFromCenteringOptions:centeringOptions]; + ASRelativeLayoutSpecPosition horizontalPosition = [self horizontalPositionFromCenteringOptions:centeringOptions]; + + if (!(self = [super initWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:child])) { return nil; } - ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); _centeringOptions = centeringOptions; _sizingOptions = sizingOptions; - [self setChild:child]; return self; } @@ -44,61 +45,36 @@ { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); _centeringOptions = centeringOptions; + + [self setHorizontalPosition:[self horizontalPositionFromCenteringOptions:centeringOptions]]; + [self setVerticalPosition:[self verticalPositionFromCenteringOptions:centeringOptions]]; } - (void)setSizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); _sizingOptions = sizingOptions; + [self setSizingOption:sizingOptions]; } -- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize +- (ASRelativeLayoutSpecPosition)horizontalPositionFromCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions { - CGSize size = { - constrainedSize.max.width, - constrainedSize.max.height - }; - - // Layout the child - const CGSize minChildSize = { - (_centeringOptions & ASCenterLayoutSpecCenteringX) != 0 ? 0 : constrainedSize.min.width, - (_centeringOptions & ASCenterLayoutSpecCenteringY) != 0 ? 0 : constrainedSize.min.height, - }; - ASLayout *sublayout = [self.child measureWithSizeRange:ASSizeRangeMake(minChildSize, constrainedSize.max)]; - - // If we have an undetermined height or width, use the child size to define the layout - // size - size = ASSizeRangeClamp(constrainedSize, { - isnan(size.width) ? sublayout.size.width : size.width, - isnan(size.height) ? sublayout.size.height : size.height - }); - - // If minimum size options are set, attempt to shrink the size to the size of the child - size = ASSizeRangeClamp(constrainedSize, { - MIN(size.width, (_sizingOptions & ASCenterLayoutSpecSizingOptionMinimumX) != 0 ? sublayout.size.width : size.width), - MIN(size.height, (_sizingOptions & ASCenterLayoutSpecSizingOptionMinimumY) != 0 ? sublayout.size.height : size.height) - }); - - // Compute the centered postion for the child - BOOL shouldCenterAlongX = (_centeringOptions & ASCenterLayoutSpecCenteringX); - BOOL shouldCenterAlongY = (_centeringOptions & ASCenterLayoutSpecCenteringY); - sublayout.position = { - ASRoundPixelValue(shouldCenterAlongX ? (size.width - sublayout.size.width) * 0.5f : 0), - ASRoundPixelValue(shouldCenterAlongY ? (size.height - sublayout.size.height) * 0.5f : 0) - }; - - return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]]; + BOOL centerX = (centeringOptions & ASCenterLayoutSpecCenteringX) != 0; + if (centerX) { + return ASRelativeLayoutSpecPositionCenter; + } else { + return ASRelativeLayoutSpecPositionStart; + } } -- (void)setChildren:(NSArray *)children +- (ASRelativeLayoutSpecPosition)verticalPositionFromCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions { - ASDisplayNodeAssert(NO, @"not supported by this layout spec"); -} - -- (NSArray *)children -{ - ASDisplayNodeAssert(NO, @"not supported by this layout spec"); - return nil; + BOOL centerY = (centeringOptions & ASCenterLayoutSpecCenteringY) != 0; + if (centerY) { + return ASRelativeLayoutSpecPositionCenter; + } else { + return ASRelativeLayoutSpecPositionStart; + } } @end diff --git a/AsyncDisplayKit/Layout/ASDimension.h b/AsyncDisplayKit/Layout/ASDimension.h index c8b0093830..3dba264468 100644 --- a/AsyncDisplayKit/Layout/ASDimension.h +++ b/AsyncDisplayKit/Layout/ASDimension.h @@ -30,7 +30,6 @@ typedef struct { typedef struct { CGSize min; CGSize max; - int32_t transitionID; } ASSizeRange; extern ASRelativeDimension const ASRelativeDimensionUnconstrained; diff --git a/AsyncDisplayKit/Layout/ASDimension.mm b/AsyncDisplayKit/Layout/ASDimension.mm index 7715e3b07a..4c7fd0a42b 100644 --- a/AsyncDisplayKit/Layout/ASDimension.mm +++ b/AsyncDisplayKit/Layout/ASDimension.mm @@ -100,7 +100,7 @@ struct _Range { { CGFloat newMin = MAX(min, other.min); CGFloat newMax = MIN(max, other.max); - if (!(newMin > newMax)) { + if (newMin <= newMax) { return {newMin, newMax}; } else { // No intersection. If we're before the other range, return our max; otherwise our min. diff --git a/AsyncDisplayKit/Layout/ASLayout.h b/AsyncDisplayKit/Layout/ASLayout.h index 073e2a6a11..41b4878461 100644 --- a/AsyncDisplayKit/Layout/ASLayout.h +++ b/AsyncDisplayKit/Layout/ASLayout.h @@ -60,7 +60,7 @@ extern BOOL CGPointIsNull(CGPoint point); * * @param size The size of this layout. * - * @param position The posiion of this layout within its parent (if available). + * @param position The position of this layout within its parent (if available). * * @param sublayouts Sublayouts belong to the new layout. */ diff --git a/AsyncDisplayKit/Layout/ASLayout.mm b/AsyncDisplayKit/Layout/ASLayout.mm index 0e15fcfc16..d6af48bcba 100644 --- a/AsyncDisplayKit/Layout/ASLayout.mm +++ b/AsyncDisplayKit/Layout/ASLayout.mm @@ -110,7 +110,7 @@ extern BOOL CGPointIsNull(CGPoint point) for (ASLayout *sublayout in context.layout.sublayouts) { // Mark layout trees that have already been flattened for future identification of immediate sublayouts - BOOL flattened = context.flattened ?: context.layout.flattened; + BOOL flattened = context.flattened ? : context.layout.flattened; queue.push({sublayout, context.absolutePosition + sublayout.position, NO, flattened}); } } diff --git a/AsyncDisplayKit/Layout/ASLayoutOptions.h b/AsyncDisplayKit/Layout/ASLayoutOptions.h deleted file mode 100644 index 7ce0f404e2..0000000000 --- a/AsyncDisplayKit/Layout/ASLayoutOptions.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@protocol ASLayoutable; - -/** - * A store for all of the options defined by ASLayoutSpec subclasses. All implementors of ASLayoutable own a - * ASLayoutOptions. When certain layoutSpecs need option values, they are read from this class. - * - * Unless you wish to create a custom layout spec, ASLayoutOptions can largerly be ignored. Instead you can access - * the layout option properties exposed in ASLayoutable directly, which will set the values in ASLayoutOptions - * behind the scenes. - */ -@interface ASLayoutOptions : NSObject - -/** - * Sets the class name for the ASLayoutOptions subclasses that will be created when a node or layoutSpec's options - * are first accessed. - * - * If you create a custom layoutSpec that includes new options, you will want to subclass ASLayoutOptions to add - * the new layout options for your layoutSpec(s). In order to make sure your subclass is created instead of an - * instance of ASLayoutOptions, call setDefaultLayoutOptionsClass: early in app launch (applicationDidFinishLaunching:) - * with your subclass's class. - * - * @param defaultLayoutOptionsClass The class of ASLayoutOptions that will be lazily created for a node or layout spec. - */ -+ (void)setDefaultLayoutOptionsClass:(Class)defaultLayoutOptionsClass; - -/** - * @return the Class of ASLayoutOptions that will be created for a node or layoutspec. Defaults to [ASLayoutOptions class]; - */ -+ (Class)defaultLayoutOptionsClass; - -#pragma mark - Subclasses should implement these! -/** - * Initializes a new ASLayoutOptions using the given layoutable to assign any intrinsic option values. - * This init function sets a sensible default value for each layout option. If you create a subclass of - * ASLayoutOptions, your subclass should do the same. - * - * @param layoutable The layoutable that will own these options. The layoutable will be used to set any intrinsic - * layoutOptions. For example, if the layoutable is an ASTextNode the ascender/descender values will get set. - * - * @return a new instance of ASLayoutOptions - */ -- (instancetype)initWithLayoutable:(id)layoutable; - -/** - * Copies the values of layoutOptions into self. This is useful when placing a layoutable inside of another. Consider - * an ASTextNode that you want to align to the baseline by putting it in an ASStackLayoutSpec. Before that, you want - * to inset the ASTextNode by placing it in an ASInsetLayoutSpec. An ASInsetLayoutSpec will not have any information - * about the ASTextNode's ascender/descender unless we copy over the layout options from ASTextNode to ASInsetLayoutSpec. - * This is done automatically and should not need to be called directly. It is listed here to make sure that any - * ASLayoutOptions subclass implements the method. - * - * @param layoutOptions The layoutOptions to copy from - */ -- (void)copyFromOptions:(ASLayoutOptions *)layoutOptions; - -#pragma mark - ASStackLayoutable - -@property (nonatomic, readwrite) CGFloat spacingBefore; -@property (nonatomic, readwrite) CGFloat spacingAfter; -@property (nonatomic, readwrite) BOOL flexGrow; -@property (nonatomic, readwrite) BOOL flexShrink; -@property (nonatomic, readwrite) ASRelativeDimension flexBasis; -@property (nonatomic, readwrite) ASStackLayoutAlignSelf alignSelf; -@property (nonatomic, readwrite) CGFloat ascender; -@property (nonatomic, readwrite) CGFloat descender; - -#pragma mark - ASStaticLayoutable - -@property (nonatomic, readwrite) ASRelativeSizeRange sizeRange; -@property (nonatomic, readwrite) CGPoint layoutPosition; - -@end - -NS_ASSUME_NONNULL_END - diff --git a/AsyncDisplayKit/Layout/ASLayoutOptions.mm b/AsyncDisplayKit/Layout/ASLayoutOptions.mm deleted file mode 100644 index ad503014bf..0000000000 --- a/AsyncDisplayKit/Layout/ASLayoutOptions.mm +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import "ASLayoutOptions.h" - -#import -#import -#import -#import "ASInternalHelpers.h" - -@interface ASLayoutOptions() -{ - ASDN::RecursiveMutex _propertyLock; -} -@end - -@implementation ASLayoutOptions - -@synthesize spacingBefore = _spacingBefore; -@synthesize spacingAfter = _spacingAfter; -@synthesize flexGrow = _flexGrow; -@synthesize flexShrink = _flexShrink; -@synthesize flexBasis = _flexBasis; -@synthesize alignSelf = _alignSelf; - -@synthesize ascender = _ascender; -@synthesize descender = _descender; - -@synthesize sizeRange = _sizeRange; -@synthesize layoutPosition = _layoutPosition; - -static Class gDefaultLayoutOptionsClass = nil; -+ (void)setDefaultLayoutOptionsClass:(Class)defaultLayoutOptionsClass -{ - gDefaultLayoutOptionsClass = defaultLayoutOptionsClass; -} - -+ (Class)defaultLayoutOptionsClass -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - if (gDefaultLayoutOptionsClass == nil) { - // If someone is asking for this and it hasn't been customized yet, use the default. - gDefaultLayoutOptionsClass = [ASLayoutOptions class]; - } - }); - return gDefaultLayoutOptionsClass; -} - -- (instancetype)init -{ - return nil; -} - -- (instancetype)initWithLayoutable:(id)layoutable -{ - self = [super init]; - if (self) { - - self.flexBasis = ASRelativeDimensionUnconstrained; - self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero)); - self.layoutPosition = CGPointZero; - - // The following properties use a default value of 0 which we do not need to assign. - // self.spacingBefore = 0; - // self.spacingAfter = 0; - // self.flexGrow = NO; - // self.flexShrink = NO; - // self.alignSelf = ASStackLayoutAlignSelfAuto; - // self.ascender = 0; - // self.descender = 0; - - [self setValuesFromLayoutable:layoutable]; - } - return self; -} - -#pragma mark - NSCopying -- (id)copyWithZone:(NSZone *)zone -{ - ASLayoutOptions *copy = [[[self class] alloc] init]; - [copy copyFromOptions:self]; - return copy; -} - -- (void)copyFromOptions:(ASLayoutOptions *)layoutOptions -{ - ASDN::MutexLocker l(_propertyLock); - self.flexBasis = layoutOptions.flexBasis; - self.spacingAfter = layoutOptions.spacingAfter; - self.spacingBefore = layoutOptions.spacingBefore; - self.flexGrow = layoutOptions.flexGrow; - self.flexShrink = layoutOptions.flexShrink; - self.alignSelf = layoutOptions.alignSelf; - - self.ascender = layoutOptions.ascender; - self.descender = layoutOptions.descender; - - self.sizeRange = layoutOptions.sizeRange; - self.layoutPosition = layoutOptions.layoutPosition; -} - -/** - * Given an id, set up layout options that are intrinsically defined by the layoutable. - * - * While this could be done in the layoutable object itself, moving the logic into the ASLayoutOptions class - * allows a custom spec to set up defaults without needing to alter the layoutable itself. For example, - * image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically - * when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the - * override of setAttributeString. However, assigning the defaults in an ASLayoutOptions subclass's - * setValuesFromLayoutable allows you to create a custom spec without the need to create a - * subclass of ASTextNode. - * - * @param layoutable The layoutable object to inspect for default intrinsic layout option values - */ -- (void)setValuesFromLayoutable:(id)layoutable -{ - ASDN::MutexLocker l(_propertyLock); - if ([layoutable isKindOfClass:[ASDisplayNode class]]) { - ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; - self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); - - if ([layoutable isKindOfClass:[ASTextNode class]]) { - ASTextNode *textNode = (ASTextNode *)layoutable; - NSAttributedString *attributedString = textNode.attributedString; - if (attributedString.length > 0) { - CGFloat screenScale = ASScreenScale(); - self.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - self.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; - } - } - - } -} - -- (CGFloat)spacingAfter -{ - ASDN::MutexLocker l(_propertyLock); - return _spacingAfter; -} - -- (void)setSpacingAfter:(CGFloat)spacingAfter -{ - ASDN::MutexLocker l(_propertyLock); - _spacingAfter = spacingAfter; -} - -- (CGFloat)spacingBefore -{ - ASDN::MutexLocker l(_propertyLock); - return _spacingBefore; -} - -- (void)setSpacingBefore:(CGFloat)spacingBefore -{ - ASDN::MutexLocker l(_propertyLock); - _spacingBefore = spacingBefore; -} - -- (BOOL)flexGrow -{ - ASDN::MutexLocker l(_propertyLock); - return _flexGrow; -} - -- (void)setFlexGrow:(BOOL)flexGrow -{ - ASDN::MutexLocker l(_propertyLock); - _flexGrow = flexGrow; -} - -- (BOOL)flexShrink -{ - ASDN::MutexLocker l(_propertyLock); - return _flexShrink; -} - -- (void)setFlexShrink:(BOOL)flexShrink -{ - ASDN::MutexLocker l(_propertyLock); - _flexShrink = flexShrink; -} - -- (ASRelativeDimension)flexBasis -{ - ASDN::MutexLocker l(_propertyLock); - return _flexBasis; -} - -- (void)setFlexBasis:(ASRelativeDimension)flexBasis -{ - ASDN::MutexLocker l(_propertyLock); - _flexBasis = flexBasis; -} - -- (ASStackLayoutAlignSelf)alignSelf -{ - ASDN::MutexLocker l(_propertyLock); - return _alignSelf; -} - -- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf -{ - ASDN::MutexLocker l(_propertyLock); - _alignSelf = alignSelf; -} - -- (CGFloat)ascender -{ - ASDN::MutexLocker l(_propertyLock); - return _ascender; -} - -- (void)setAscender:(CGFloat)ascender -{ - ASDN::MutexLocker l(_propertyLock); - _ascender = ascender; -} - -- (CGFloat)descender -{ - ASDN::MutexLocker l(_propertyLock); - return _descender; -} - -- (void)setDescender:(CGFloat)descender -{ - ASDN::MutexLocker l(_propertyLock); - _descender = descender; -} - -- (ASRelativeSizeRange)sizeRange -{ - ASDN::MutexLocker l(_propertyLock); - return _sizeRange; -} - -- (void)setSizeRange:(ASRelativeSizeRange)sizeRange -{ - ASDN::MutexLocker l(_propertyLock); - _sizeRange = sizeRange; -} - -- (CGPoint)layoutPosition -{ - ASDN::MutexLocker l(_propertyLock); - return _layoutPosition; -} - -- (void)setLayoutPosition:(CGPoint)layoutPosition -{ - ASDN::MutexLocker l(_propertyLock); - _layoutPosition = layoutPosition; -} - -@end diff --git a/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm b/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm deleted file mode 100644 index 64b3f7b629..0000000000 --- a/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import "ASLayoutOptionsPrivate.h" -#import -#import "ASThread.h" - - -/** - * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties - * in ASLayoutable that are used as layoutOptions when a node or spec is used in a layout spec. - * These properties are provided for convenience, as they are forwards to the node or spec's - * ASLayoutOptions class. Instead of duplicating the property forwarding in both classes, we - * create a define that allows us to easily implement the forwards in one place. - * - * If you create a custom layout spec, we recommend this stragety if you decide to extend - * ASDisplayNode and ASLAyoutSpec to provide convenience properties for any options that your - * layoutSpec may require. - */ -#define ASLayoutOptionsForwarding \ -- (ASLayoutOptions *)layoutOptions\ -{\ -ASDN::MutexLocker l(_layoutOptionsLock);\ -if (_layoutOptions == nil) {\ -_layoutOptions = [[[ASLayoutOptions defaultLayoutOptionsClass] alloc] initWithLayoutable:self];\ -}\ -return _layoutOptions;\ -}\ -\ -- (CGFloat)spacingBefore\ -{\ -return self.layoutOptions.spacingBefore;\ -}\ -\ -- (void)setSpacingBefore:(CGFloat)spacingBefore\ -{\ -self.layoutOptions.spacingBefore = spacingBefore;\ -}\ -\ -- (CGFloat)spacingAfter\ -{\ -return self.layoutOptions.spacingAfter;\ -}\ -\ -- (void)setSpacingAfter:(CGFloat)spacingAfter\ -{\ -self.layoutOptions.spacingAfter = spacingAfter;\ -}\ -\ -- (BOOL)flexGrow\ -{\ -return self.layoutOptions.flexGrow;\ -}\ -\ -- (void)setFlexGrow:(BOOL)flexGrow\ -{\ -self.layoutOptions.flexGrow = flexGrow;\ -}\ -\ -- (BOOL)flexShrink\ -{\ -return self.layoutOptions.flexShrink;\ -}\ -\ -- (void)setFlexShrink:(BOOL)flexShrink\ -{\ -self.layoutOptions.flexShrink = flexShrink;\ -}\ -\ -- (ASRelativeDimension)flexBasis\ -{\ -return self.layoutOptions.flexBasis;\ -}\ -\ -- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ -{\ -self.layoutOptions.flexBasis = flexBasis;\ -}\ -\ -- (ASStackLayoutAlignSelf)alignSelf\ -{\ -return self.layoutOptions.alignSelf;\ -}\ -\ -- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ -{\ - self.layoutOptions.alignSelf = alignSelf;\ -}\ -\ -- (CGFloat)ascender\ -{\ - return self.layoutOptions.ascender;\ -}\ -\ -- (void)setAscender:(CGFloat)ascender\ -{\ - self.layoutOptions.ascender = ascender;\ -}\ -\ -- (CGFloat)descender\ -{\ - return self.layoutOptions.descender;\ -}\ -\ -- (void)setDescender:(CGFloat)descender\ -{\ - self.layoutOptions.descender = descender;\ -}\ -\ -- (ASRelativeSizeRange)sizeRange\ -{\ - return self.layoutOptions.sizeRange;\ -}\ -\ -- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ -{\ - self.layoutOptions.sizeRange = sizeRange;\ -}\ -\ -- (CGPoint)layoutPosition\ -{\ - return self.layoutOptions.layoutPosition;\ -}\ -\ -- (void)setLayoutPosition:(CGPoint)position\ -{\ - self.layoutOptions.layoutPosition = position;\ -}\ - - -@implementation ASDisplayNode(ASLayoutOptions) -ASLayoutOptionsForwarding -@end - -@implementation ASLayoutSpec(ASLayoutOptions) -ASLayoutOptionsForwarding -@end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index da6de78e0f..dcb9b33246 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -25,13 +25,15 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init; +@property (nullable, nonatomic, weak) id parent; + /** * Adds a child to this layout spec using a default identifier. * * @param child A child to be added. * * @discussion Every ASLayoutSpec must act on at least one child. The ASLayoutSpec base class takes the - * reponsibility of holding on to the spec children. Some layout specs, like ASInsetLayoutSpec, + * responsibility of holding on to the spec children. Some layout specs, like ASInsetLayoutSpec, * only require a single child. * * For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example) @@ -50,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN * @param identifier An identifier associated with the child. * * @discussion Every ASLayoutSpec must act on at least one child. The ASLayoutSpec base class takes the - * reponsibility of holding on to the spec children. Some layout specs, like ASInsetLayoutSpec, + * responsibility of holding on to the spec children. Some layout specs, like ASInsetLayoutSpec, * only require a single child. * * For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example) diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index abb428ebd1..a74dcd941d 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -8,29 +8,33 @@ * */ -#import "ASLayoutOptionsPrivate.h" +#import "ASLayoutSpec.h" #import "ASAssert.h" #import "ASBaseDefines.h" +#import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" #import "ASLayout.h" -#import "ASLayoutOptions.h" #import "ASThread.h" + #import static NSString * const kDefaultChildKey = @"kDefaultChildKey"; static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; -@interface ASLayoutSpec() +@interface ASLayoutSpec() { + ASEnvironmentState _environmentState; + ASDN::RecursiveMutex _propertyLock; +} @property (nonatomic, strong) NSMutableDictionary *layoutChildren; @end @implementation ASLayoutSpec // these dynamic properties all defined in ASLayoutOptionsPrivate.m -@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition; @synthesize layoutChildren = _layoutChildren; @synthesize isFinalLayoutable = _isFinalLayoutable; @@ -40,6 +44,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return nil; } _isMutable = YES; + _environmentState = ASEnvironmentStateMakeDefault(); + return self; } @@ -75,7 +81,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { - [finalLayoutable.layoutOptions copyFromOptions:child.layoutOptions]; + // Layout options state of child needs to be copied to final layoutable, but don't override customized values. + ASEnvironmentStatePropagateUp(finalLayoutable, child.environmentState.layoutOptionsState); return finalLayoutable; } } @@ -90,6 +97,16 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return _layoutChildren; } +- (void)setParent:(id)parent +{ + // FIXME: Locking should be evaluated here. _parent is not widely used yet, though. + _parent = parent; + + if ([parent supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(parent, self.environmentState.layoutOptionsState); + } +} + - (void)setChild:(id)child; { [self setChild:child forIdentifier:kDefaultChildKey]; @@ -98,7 +115,13 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; - (void)setChild:(id)child forIdentifier:(NSString *)identifier { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); - self.layoutChildren[identifier] = [self layoutableToAddFromLayoutable:child];; + id finalLayoutable = [self layoutableToAddFromLayoutable:child]; + self.layoutChildren[identifier] = finalLayoutable; + if ([finalLayoutable isKindOfClass:[ASLayoutSpec class]]) { + [(ASLayoutSpec *)finalLayoutable setParent:self]; // This will trigger upward propogation if needed. + } else if ([self supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(self, finalLayoutable.environmentState.layoutOptionsState); // Probably an ASDisplayNode + } } - (void)setChildren:(NSArray *)children @@ -128,6 +151,30 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return self.layoutChildren[kDefaultChildrenKey]; } + +#pragma mark - ASEnvironment + +- (ASEnvironmentState)environmentState +{ + return _environmentState; +} + +- (void)setEnvironmentState:(ASEnvironmentState)environmentState +{ + _environmentState = environmentState; +} + +// Subclasses can override this method to return NO, because upward propagation is not enabled if a layout +// specification has more than one child. Currently ASStackLayoutSpec and ASStaticLayoutSpec are currently +// the specifications that are known to have more than one. +- (BOOL)supportsUpwardPropagation +{ + return YES; +} + +ASEnvironmentLayoutOptionsForwarding +ASEnvironmentLayoutExtensibilityForwarding + @end @implementation ASLayoutSpec (Debugging) diff --git a/AsyncDisplayKit/Layout/ASLayoutable.h b/AsyncDisplayKit/Layout/ASLayoutable.h index 4653e38def..325a81535c 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.h +++ b/AsyncDisplayKit/Layout/ASLayoutable.h @@ -15,6 +15,8 @@ #import #import +#import +#import @class ASLayout; @class ASLayoutSpec; @@ -35,9 +37,9 @@ NS_ASSUME_NONNULL_BEGIN * These layout options are all stored in an ASLayoutOptions class (that is defined in ASLayoutablePrivate). * Generally you needn't worry about the layout options class, as the layoutable protocols allow all direct * access to the options via convenience properties. If you are creating custom layout spec, then you can - * extend the backing layout options class to accomodate any new layout options. + * extend the backing layout options class to accommodate any new layout options. */ -@protocol ASLayoutable +@protocol ASLayoutable /** * @abstract Calculate a layout based on given size range. diff --git a/AsyncDisplayKit/Layout/ASLayoutable.mm b/AsyncDisplayKit/Layout/ASLayoutable.mm new file mode 100644 index 0000000000..23fd59e9ff --- /dev/null +++ b/AsyncDisplayKit/Layout/ASLayoutable.mm @@ -0,0 +1,83 @@ +// +// ASLayoutablePrivate.mm +// AsyncDisplayKit +// +// Created by Huy Nguyen on 3/27/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASLayoutablePrivate.h" +#import "ASInternalHelpers.h" +#import "ASEnvironmentInternal.h" +#import "ASDisplayNodeInternal.h" +#import "ASTextNode.h" +#import "ASLayoutSpec.h" + +#import "pthread.h" +#import +#import +#import "ASThread.h" + +int32_t const ASLayoutableContextInvalidTransitionID = 0; +int32_t const ASLayoutableContextDefaultTransitionID = ASLayoutableContextInvalidTransitionID + 1; + +static inline ASLayoutableContext _ASLayoutableContextMake(int32_t transitionID, BOOL needsVisualizeNode) +{ + struct ASLayoutableContext context; + context.transitionID = transitionID; + context.needsVisualizeNode = needsVisualizeNode; + return context; +} + +static inline BOOL _IsValidTransitionID(int32_t transitionID) +{ + return transitionID > ASLayoutableContextInvalidTransitionID; +} + +struct ASLayoutableContext const ASLayoutableContextNull = _ASLayoutableContextMake(ASLayoutableContextInvalidTransitionID, NO); + +BOOL ASLayoutableContextIsNull(struct ASLayoutableContext context) +{ + return !_IsValidTransitionID(context.transitionID); +} + +ASLayoutableContext ASLayoutableContextMake(int32_t transitionID, BOOL needsVisualizeNode) +{ + NSCAssert(_IsValidTransitionID(transitionID), @"Invalid transition ID"); + return _ASLayoutableContextMake(transitionID, needsVisualizeNode); +} + +// Note: This is a non-recursive static lock. If it needs to be recursive, use ASDISPLAYNODE_MUTEX_RECURSIVE_INITIALIZER +static ASDN::StaticMutex _layoutableContextLock = ASDISPLAYNODE_MUTEX_INITIALIZER; +static std::map layoutableContextMap; + +static inline mach_port_t ASLayoutableGetCurrentContextKey() +{ + return pthread_mach_thread_np(pthread_self()); +} + +void ASLayoutableSetCurrentContext(struct ASLayoutableContext context) +{ + const mach_port_t key = ASLayoutableGetCurrentContextKey(); + ASDN::StaticMutexLocker l(_layoutableContextLock); + layoutableContextMap[key] = context; +} + +struct ASLayoutableContext ASLayoutableGetCurrentContext() +{ + const mach_port_t key = ASLayoutableGetCurrentContextKey(); + ASDN::StaticMutexLocker l(_layoutableContextLock); + const auto it = layoutableContextMap.find(key); + if (it != layoutableContextMap.end()) { + // Found an interator with above key. "it->first" is the key itself, "it->second" is the context value. + return it->second; + } + return ASLayoutableContextNull; +} + +void ASLayoutableClearCurrentContext() +{ + const mach_port_t key = ASLayoutableGetCurrentContextKey(); + ASDN::StaticMutexLocker l(_layoutableContextLock); + layoutableContextMap.erase(key); +} diff --git a/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h b/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h new file mode 100644 index 0000000000..62cadd3ee2 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h @@ -0,0 +1,25 @@ +// +// ASLayoutableExtensibility.h +// AsyncDisplayKit +// +// Created by Michael Schneider on 3/29/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +@protocol ASLayoutableExtensibility + +// The maximum number of extended values per type are defined in ASEnvironment.h above the ASEnvironmentStateExtensions +// struct definition. If you try to set a value at an index after the maximum it will throw an assertion. + +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx; +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx; + +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx; +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx; + +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx; +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx; + +@end diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index f52dd54ad6..ce2de20f6d 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -11,9 +11,29 @@ #import @class ASLayoutSpec; -@class ASLayoutOptions; @protocol ASLayoutable; +struct ASLayoutableContext { + int32_t transitionID; + BOOL needsVisualizeNode; +}; + +extern int32_t const ASLayoutableContextInvalidTransitionID; + +extern int32_t const ASLayoutableContextDefaultTransitionID; + +extern struct ASLayoutableContext const ASLayoutableContextNull; + +extern BOOL ASLayoutableContextIsNull(struct ASLayoutableContext context); + +extern struct ASLayoutableContext ASLayoutableContextMake(int32_t transitionID, BOOL needsVisualizeNode); + +extern void ASLayoutableSetCurrentContext(struct ASLayoutableContext context); + +extern struct ASLayoutableContext ASLayoutableGetCurrentContext(); + +extern void ASLayoutableClearCurrentContext(); + /** * The base protocol for ASLayoutable. Generally the methods/properties in this class do not need to be * called by the end user and are only called internally. However, there may be a case where the methods are useful. @@ -39,9 +59,211 @@ */ @property (nonatomic, assign) BOOL isFinalLayoutable; +@end + + +#pragma mark - ASLayoutOptionsForwarding /** - * The class that holds all of the layoutOptions set on an ASLayoutable. + * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties + * in ASLayoutable that are used when a node or spec is used in a layout spec. + * These properties are provided for convenience, as they are forwards to the node or spec's + * properties. Instead of duplicating the property forwarding in both classes, we + * create a define that allows us to easily implement the forwards in one place. + * + * If you create a custom layout spec, we recommend this stragety if you decide to extend + * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your + * layoutSpec may require. */ -@property (nonatomic, strong, readonly) ASLayoutOptions *layoutOptions; -@end + +#define ASEnvironmentLayoutOptionsForwarding \ +- (void)propagateUpLayoutOptionsState\ +{\ + id parent = [self parent];\ + if ([parent supportsUpwardPropagation]) {\ + ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState);\ + }\ +}\ +\ +- (CGFloat)spacingAfter\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.spacingAfter;\ +}\ +\ +- (void)setSpacingAfter:(CGFloat)spacingAfter\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.spacingAfter = spacingAfter;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)spacingBefore\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.spacingBefore;\ +}\ +\ +- (void)setSpacingBefore:(CGFloat)spacingBefore\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.spacingBefore = spacingBefore;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)flexGrow\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexGrow;\ +}\ +\ +- (void)setFlexGrow:(BOOL)flexGrow\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexGrow = flexGrow;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)flexShrink\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexShrink;\ +}\ +\ +- (void)setFlexShrink:(BOOL)flexShrink\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexShrink = flexShrink;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASRelativeDimension)flexBasis\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexBasis;\ +}\ +\ +- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexBasis = flexBasis;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASStackLayoutAlignSelf)alignSelf\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.alignSelf;\ +}\ +\ +- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.alignSelf = alignSelf;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)ascender\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.ascender;\ +}\ +\ +- (void)setAscender:(CGFloat)ascender\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.ascender = ascender;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)descender\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.descender;\ +}\ +\ +- (void)setDescender:(CGFloat)descender\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.descender = descender;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASRelativeSizeRange)sizeRange\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.sizeRange;\ +}\ +\ +- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.sizeRange = sizeRange;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGPoint)layoutPosition\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.layoutPosition;\ +}\ +\ +- (void)setLayoutPosition:(CGPoint)layoutPosition\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.layoutPosition = layoutPosition;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ + + +#pragma mark - ASLayoutableExtensibility + +#define ASEnvironmentLayoutExtensibilityForwarding \ +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx\ +{\ + _propertyLock.lock();\ + _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);\ +}\ +\ +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx\ +{\ + _propertyLock.lock();\ + _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);\ + _propertyLock.unlock();\ +}\ +\ +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);\ +}\ +\ +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx\ +{\ + _propertyLock.lock();\ + _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);\ + _propertyLock.unlock();\ +}\ +\ +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);\ +}\ diff --git a/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h new file mode 100644 index 0000000000..ddc88c0664 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h @@ -0,0 +1,73 @@ +// +// ASRelativeLayoutSpec.h +// AsyncDisplayKit +// +// Created by Samuel Stow on 12/31/15. +// + +#import + +/** How the child is positioned within the spec. */ +typedef NS_OPTIONS(NSUInteger, ASRelativeLayoutSpecPosition) { + /** The child is positioned at point 0 relatively to the layout axis (ie left / top most) */ + ASRelativeLayoutSpecPositionStart = 0, + /** The child is centered along the specified axis */ + ASRelativeLayoutSpecPositionCenter = 1 << 0, + /** The child is positioned at the maximum point of the layout axis (ie right / bottom most) */ + ASRelativeLayoutSpecPositionEnd = 1 << 1, +}; + +/** How much space the spec will take up. */ +typedef NS_OPTIONS(NSUInteger, ASRelativeLayoutSpecSizingOption) { + /** The spec will take up the maximum size possible */ + ASRelativeLayoutSpecSizingOptionDefault, + /** The spec will take up the minimum size possible along the X axis */ + ASRelativeLayoutSpecSizingOptionMinimumWidth = 1 << 0, + /** The spec will take up the minimum size possible along the Y axis */ + ASRelativeLayoutSpecSizingOptionMinimumHeight = 1 << 1, + /** Convenience option to take up the minimum size along both the X and Y axis */ + ASRelativeLayoutSpecSizingOptionMinimumSize = ASRelativeLayoutSpecSizingOptionMinimumWidth | ASRelativeLayoutSpecSizingOptionMinimumHeight, +}; + +NS_ASSUME_NONNULL_BEGIN + +/** Lays out a single layoutable child and positions it within the layout bounds according to vertical and horizontal positional specifiers. + * Can position the child at any of the 4 corners, or the middle of any of the 4 edges, as well as the center - similar to "9-part" image areas. + */ +@interface ASRelativeLayoutSpec : ASLayoutSpec + +// You may create a spec with alloc / init, then set any non-default properties; or use a convenience initialize that accepts all properties. +@property (nonatomic, assign) ASRelativeLayoutSpecPosition horizontalPosition; +@property (nonatomic, assign) ASRelativeLayoutSpecPosition verticalPosition; +@property (nonatomic, assign) ASRelativeLayoutSpecSizingOption sizingOption; + +/*! + * @discussion convenience constructor for a ASRelativeLayoutSpec + * @param horizontalPosition how to position the item on the horizontal (x) axis + * @param verticalPosition how to position the item on the vertical (y) axis + * @param sizingOption how much size to take up + * @param child the child to layout + * @return a configured ASRelativeLayoutSpec + */ ++ (instancetype)relativePositionLayoutSpecWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition + verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition + sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption + child:(id)child; + +/*! + * @discussion convenience initializer for a ASRelativeLayoutSpec + * @param horizontalPosition how to position the item on the horizontal (x) axis + * @param verticalPosition how to position the item on the vertical (y) axis + * @param sizingOption how much size to take up + * @param child the child to layout + * @return a configured ASRelativeLayoutSpec + */ +- (instancetype)initWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition + verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition + sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption + child:(id)child; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm new file mode 100644 index 0000000000..7a1a0ea5e0 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm @@ -0,0 +1,117 @@ +// +// ASRelativeLayoutSpec.mm +// AsyncDisplayKit +// +// Created by Samuel Stow on 12/31/15. +// + +#import "ASRelativeLayoutSpec.h" + +#import "ASInternalHelpers.h" +#import "ASLayout.h" + +@implementation ASRelativeLayoutSpec + +- (instancetype)initWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption child:(id)child +{ + if (!(self = [super init])) { + return nil; + } + ASDisplayNodeAssertNotNil(child, @"Child cannot be nil"); + _horizontalPosition = horizontalPosition; + _verticalPosition = verticalPosition; + _sizingOption = sizingOption; + [self setChild:child]; + return self; +} + ++ (instancetype)relativePositionLayoutSpecWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption child:(id)child +{ + return [[self alloc] initWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOption child:child]; +} + +- (void)setHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _horizontalPosition = horizontalPosition; +} + +- (void)setVerticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition { + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _verticalPosition = verticalPosition; +} + +- (void)setSizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption +{ + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + _sizingOption = sizingOption; +} + +- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize +{ + CGSize size = { + constrainedSize.max.width, + constrainedSize.max.height + }; + + BOOL reduceWidth = (_horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0 || + (_horizontalPosition & ASRelativeLayoutSpecPositionEnd) != 0; + + BOOL reduceHeight = (_verticalPosition & ASRelativeLayoutSpecPositionCenter) != 0 || + (_verticalPosition & ASRelativeLayoutSpecPositionEnd) != 0; + + // Layout the child + const CGSize minChildSize = { + reduceWidth ? 0 : constrainedSize.min.width, + reduceHeight ? 0 : constrainedSize.min.height, + }; + ASLayout *sublayout = [self.child measureWithSizeRange:ASSizeRangeMake(minChildSize, constrainedSize.max)]; + + // If we have an undetermined height or width, use the child size to define the layout + // size + size = ASSizeRangeClamp(constrainedSize, { + isfinite(size.width) == NO ? sublayout.size.width : size.width, + isfinite(size.height) == NO ? sublayout.size.height : size.height + }); + + // If minimum size options are set, attempt to shrink the size to the size of the child + size = ASSizeRangeClamp(constrainedSize, { + MIN(size.width, (_sizingOption & ASRelativeLayoutSpecSizingOptionMinimumWidth) != 0 ? sublayout.size.width : size.width), + MIN(size.height, (_sizingOption & ASRelativeLayoutSpecSizingOptionMinimumHeight) != 0 ? sublayout.size.height : size.height) + }); + + // Compute the position for the child on each axis according to layout parameters + CGFloat xPosition = [self proportionOfAxisForAxisPosition:_horizontalPosition]; + CGFloat yPosition = [self proportionOfAxisForAxisPosition:_verticalPosition]; + + sublayout.position = { + ASRoundPixelValue((size.width - sublayout.size.width) * xPosition), + ASRoundPixelValue((size.height - sublayout.size.height) * yPosition) + }; + + return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]]; +} + +- (void)setChildren:(NSArray *)children +{ + ASDisplayNodeAssert(NO, @"not supported by this layout spec"); +} + +- (NSArray *)children +{ + ASDisplayNodeAssert(NO, @"not supported by this layout spec"); + return nil; +} + +- (CGFloat)proportionOfAxisForAxisPosition:(ASRelativeLayoutSpecPosition)position +{ + if ((position & ASRelativeLayoutSpecPositionCenter) != 0) { + return 0.5f; + } else if ((position & ASRelativeLayoutSpecPositionEnd) != 0) { + return 1.0f; + } else { + return 0.0f; + } +} + +@end diff --git a/AsyncDisplayKit/Layout/ASStackLayoutDefines.h b/AsyncDisplayKit/Layout/ASStackLayoutDefines.h index 2ed646ab67..48c0667a6b 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutDefines.h +++ b/AsyncDisplayKit/Layout/ASStackLayoutDefines.h @@ -8,6 +8,8 @@ * */ +#import "ASBaseDefines.h" + /** The direction children are stacked in */ typedef NS_ENUM(NSUInteger, ASStackLayoutDirection) { /** Children are stacked vertically */ @@ -88,11 +90,19 @@ typedef NS_ENUM(NSUInteger, ASHorizontalAlignment) { /** No alignment specified. Default value */ ASHorizontalAlignmentNone, /** Left aligned */ - ASAlignmentLeft, + ASHorizontalAlignmentLeft, /** Center aligned */ - ASAlignmentMiddle, + ASHorizontalAlignmentMiddle, /** Right aligned */ - ASAlignmentRight, + ASHorizontalAlignmentRight, + + // After 2.0 has landed, we'll add ASDISPLAYNODE_DEPRECATED here - for now, avoid triggering errors for projects with -Werror + /** @deprecated Use ASHorizontalAlignmentLeft instead */ + ASAlignmentLeft = ASHorizontalAlignmentLeft, + /** @deprecated Use ASHorizontalAlignmentMiddle instead */ + ASAlignmentMiddle = ASHorizontalAlignmentMiddle, + /** @deprecated Use ASHorizontalAlignmentRight instead */ + ASAlignmentRight = ASHorizontalAlignmentRight, }; /** Orientation of children along vertical axis */ @@ -100,9 +110,17 @@ typedef NS_ENUM(NSUInteger, ASVerticalAlignment) { /** No alignment specified. Default value */ ASVerticalAlignmentNone, /** Top aligned */ - ASAlignmentTop, + ASVerticalAlignmentTop, /** Center aligned */ - ASAlignmentCenter, + ASVerticalAlignmentCenter, /** Bottom aligned */ - ASAlignmentBottom, + ASVerticalAlignmentBottom, + + // After 2.0 has landed, we'll add ASDISPLAYNODE_DEPRECATED here - for now, avoid triggering errors for projects with -Werror + /** @deprecated Use ASVerticalAlignmentTop instead */ + ASAlignmentTop = ASVerticalAlignmentTop, + /** @deprecated Use ASVerticalAlignmentCenter instead */ + ASAlignmentCenter = ASVerticalAlignmentCenter, + /** @deprecated Use ASVerticalAlignmentBottom instead */ + ASAlignmentBottom = ASVerticalAlignmentBottom, }; diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm index 76539bf57a..26b6d449c7 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm @@ -198,6 +198,15 @@ @end +@implementation ASStackLayoutSpec (ASEnvironment) + +- (BOOL)supportsUpwardPropagation +{ + return NO; +} + +@end + @implementation ASStackLayoutSpec (Debugging) #pragma mark - ASLayoutableAsciiArtProtocol diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index 2d0edba4cd..a727376a57 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -11,7 +11,6 @@ #import "ASStaticLayoutSpec.h" #import "ASLayoutSpecUtilities.h" -#import "ASLayoutOptions.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -86,6 +85,15 @@ @end +@implementation ASStaticLayoutSpec (ASEnvironment) + +- (BOOL)supportsUpwardPropagation +{ + return NO; +} + +@end + @implementation ASStaticLayoutSpec (Debugging) #pragma mark - ASLayoutableAsciiArtProtocol diff --git a/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm b/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm index 98e8a2bc68..862497b86a 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm +++ b/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm @@ -64,7 +64,7 @@ static void __ASDisplayLayerIncrementConcurrentDisplayCount(BOOL displayIsAsync, */ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync, BOOL isRasterizing) { - // Displays while rasterizing are not counted as concurrent displays, becuase they draw in serial when their rasterizing container displays. + // Displays while rasterizing are not counted as concurrent displays, because they draw in serial when their rasterizing container displays. if (isRasterizing) { return; } @@ -92,7 +92,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync, BOOL rasterizingFromAscendent = (_hierarchyState & ASHierarchyStateRasterized); - // if super node is rasterizing descendents, subnodes will not have had layout calls because they don't have layers + // if super node is rasterizing descendants, subnodes will not have had layout calls because they don't have layers if (rasterizingFromAscendent) { [self __layout]; } @@ -370,7 +370,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync, // while synchronizing the final application of the results to the layer's contents property (completionBlock). // First, look to see if we are expected to join a parent's transaction container. - CALayer *containerLayer = _layer.asyncdisplaykit_parentTransactionContainer ?: _layer; + CALayer *containerLayer = _layer.asyncdisplaykit_parentTransactionContainer ? : _layer; // In the case that a transaction does not yet exist (such as for an individual node outside of a container), // this call will allocate the transaction and add it to _ASAsyncTransactionGroup. diff --git a/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h b/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h index 79f2b2e273..07cb3440b8 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h +++ b/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h @@ -16,13 +16,12 @@ #import "ASDisplayNode.h" #import "ASSentinel.h" #import "ASThread.h" -#import "ASLayoutOptions.h" #import "_ASDisplayLayer.h" NS_ASSUME_NONNULL_BEGIN /** - Hierarchy state is propogated from nodes to all of their children when certain behaviors are required from the subtree. + Hierarchy state is propagated from nodes to all of their children when certain behaviors are required from the subtree. Examples include rasterization and external driving of the .interfaceState property. By passing this information explicitly, performance is optimized by avoiding iteration up the supernode chain. Lastly, this avoidance of supernode traversal protects against the possibility of deadlocks when a supernode is @@ -41,9 +40,9 @@ typedef NS_OPTIONS(NSUInteger, ASHierarchyState) ASHierarchyStateRasterized = 1 << 0, /** The node or one of its supernodes is managed by a class like ASRangeController. Most commonly, these nodes are ASCellNode objects or a subnode of one, and are used in ASTableView or ASCollectionView. - These nodes also recieve regular updates to the .interfaceState property with more detailed status information. */ + These nodes also receive regular updates to the .interfaceState property with more detailed status information. */ ASHierarchyStateRangeManaged = 1 << 1, - /** Down-propogated version of _flags.visibilityNotificationsDisabled. This flag is very rarely set, but by having it + /** Down-propagated version of _flags.visibilityNotificationsDisabled. This flag is very rarely set, but by having it locally available to nodes, they do not have to walk up supernodes at the critical points it is checked. */ ASHierarchyStateTransitioningSupernodes = 1 << 2, /** One of the supernodes of this node is performing a transition. @@ -56,6 +55,11 @@ inline BOOL ASHierarchyStateIncludesLayoutPending(ASHierarchyState hierarchyStat return ((hierarchyState & ASHierarchyStateLayoutPending) == ASHierarchyStateLayoutPending); } +inline BOOL ASHierarchyStateIncludesRangeManaged(ASHierarchyState hierarchyState) +{ + return ((hierarchyState & ASHierarchyStateRangeManaged) == ASHierarchyStateRangeManaged); +} + @interface ASDisplayNode () { @protected @@ -91,11 +95,19 @@ inline BOOL ASHierarchyStateIncludesLayoutPending(ASHierarchyState hierarchyStat */ @property (nonatomic, readwrite) ASHierarchyState hierarchyState; +/** + * @abstract Return if the node is range managed or not + * + * @discussion Currently only set interface state on nodes in table and collection views. For other nodes, if they are + * in the hierarchy we enable all ASInterfaceState types with `ASInterfaceStateInHierarchy`, otherwise `None`. + */ +- (BOOL)supportsRangeManagedInterfaceState; + // The two methods below will eventually be exposed, but their names are subject to change. /** - * @abstract Ensure that all rendering is complete for this node and its descendents. + * @abstract Ensure that all rendering is complete for this node and its descendants. * - * @discussion Calling this method on the main thread after a node is added to the view heirarchy will ensure that + * @discussion Calling this method on the main thread after a node is added to the view hierarchy will ensure that * placeholder states are never visible to the user. It is used by ASTableView, ASCollectionView, and ASViewController * to implement their respective ".neverShowPlaceholders" option. * diff --git a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm index 68876415a7..bf0b9f200d 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm +++ b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm @@ -302,7 +302,7 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo if (_hierarchyState & ASHierarchyStateRasterized) { ASPerformBlockOnMainThread(^{ // The below operation must be performed on the main thread to ensure against an extremely rare deadlock, where a parent node - // begins materializing the view / layer heirarchy (locking itself or a descendant) while this node walks up + // begins materializing the view / layer hierarchy (locking itself or a descendant) while this node walks up // the tree and requires locking that node to access .shouldRasterizeDescendants. // For this reason, this method should be avoided when possible. Use _hierarchyState & ASHierarchyStateRasterized. ASDisplayNodeAssertMainThread(); diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index e491aac0c6..e8930b9865 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -16,9 +16,9 @@ #import "ASDisplayNode.h" #import "ASSentinel.h" #import "ASThread.h" -#import "ASLayoutOptions.h" #import "_ASTransitionContext.h" #import "ASDisplayNodeLayoutContext.h" +#import "ASEnvironment.h" #include @@ -70,6 +70,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo unsigned shouldRasterizeDescendants:1; unsigned shouldBypassEnsureDisplay:1; unsigned displaySuspended:1; + unsigned shouldAnimateSizeChanges:1; unsigned hasCustomDrawingPriority:1; // whether custom drawing is enabled @@ -96,6 +97,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo // This is the desired contentsScale, not the scale at which the layer's contents should be displayed CGFloat _contentsScaleForDisplay; + ASEnvironmentState _environmentState; ASLayout *_layout; ASSizeRange _constrainedSize; @@ -139,7 +141,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo + (void)scheduleNodeForRecursiveDisplay:(ASDisplayNode *)node; // The _ASDisplayLayer backing the node, if any. -@property (nonatomic, readonly, retain) _ASDisplayLayer *asyncLayer; +@property (nonatomic, readonly, strong) _ASDisplayLayer *asyncLayer; // Bitmask to check which methods an object overrides. @property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides; diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h new file mode 100644 index 0000000000..e69bed23a0 --- /dev/null +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironment.h" + +#pragma once + +enum class ASEnvironmentStatePropagation { DOWN, UP }; + + +#pragma mark - Set and get extensible values for layout options + +void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id object, int idx, BOOL value); +BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id object, int idx); + +void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id object, int idx, NSInteger value); +NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id object, int idx); + +void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id object, int idx, UIEdgeInsets value); +UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id object, int idx); + + +#pragma mark - Traversing an ASEnvironment Tree + +void ASEnvironmentPerformBlockOnObjectAndChildren(id object, void(^block)(id object)); +void ASEnvironmentPerformBlockOnObjectAndParents(id object, void(^block)(id object)); + + +#pragma mark - Merging + +static const struct ASEnvironmentStateExtensions ASEnvironmentDefaultStateExtensions = {}; + +static const struct ASEnvironmentLayoutOptionsState ASEnvironmentDefaultLayoutOptionsState = {}; +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation); + + +static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation); + + +#pragma mark - Propagation + +template +void ASEnvironmentStatePropagateDown(id object, ASEnvironmentStateType state) { + ASEnvironmentPerformBlockOnObjectAndChildren(object, ^(id node) { + object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::DOWN); + }); +} + +template +void ASEnvironmentStatePropagateUp(id object, ASEnvironmentStateType state) { + ASEnvironmentPerformBlockOnObjectAndParents(object, ^(id node) { + object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::UP); + }); +} + +template +void ASEnvironmentStateApply(id object, ASEnvironmentStateType& state, ASEnvironmentStatePropagation propagate) { + if (propagate == ASEnvironmentStatePropagation::DOWN) { + ASEnvironmentStatePropagateUp(object, state); + } else if (propagate == ASEnvironmentStatePropagation::UP) { + ASEnvironmentStatePropagateDown(object, state); + } +} diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm new file mode 100644 index 0000000000..909787a560 --- /dev/null +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironmentInternal.h" + +#import + +//#define LOG(...) NSLog(__VA_ARGS__) +#define LOG(...) + +#pragma mark - Traversing an ASEnvironment Tree + +void ASEnvironmentPerformBlockOnObjectAndChildren(id object, void(^block)(id node)) +{ + if (!object) { + return; + } + + std::queue> queue; + queue.push(object); + + while (!queue.empty()) { + id object = queue.front(); queue.pop(); + + block(object); + + for (id child in [object children]) { + queue.push(child); + } + } +} + +void ASEnvironmentPerformBlockOnObjectAndParents(id object, void(^block)(id node)) +{ + while (object) { + block(object); + object = [object parent]; + } +} + + +#pragma mark - Set and get extensible values from state structs + +void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id object, int idx, BOOL value) +{ + NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Setting index outside of max bool extensions space"); + + ASEnvironmentState state = object.environmentState; + state.layoutOptionsState._extensions.boolExtensions[idx] = value; + object.environmentState = state; +} + +BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id object, int idx) +{ + NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space"); + return object.environmentState.layoutOptionsState._extensions.boolExtensions[idx]; +} + +void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id object, int idx, NSInteger value) +{ + NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Setting index outside of max integer extensions space"); + + ASEnvironmentState state = object.environmentState; + state.layoutOptionsState._extensions.integerExtensions[idx] = value; + object.environmentState = state; +} + +NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id object, int idx) +{ + NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space"); + return object.environmentState.layoutOptionsState._extensions.integerExtensions[idx]; +} + +void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id object, int idx, UIEdgeInsets value) +{ + NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space"); + + ASEnvironmentState state = object.environmentState; + state.layoutOptionsState._extensions.edgeInsetsExtensions[idx] = value; + object.environmentState = state; +} + +UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id object, int idx) +{ + NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space"); + return object.environmentState.layoutOptionsState._extensions.edgeInsetsExtensions[idx]; +} + + +#pragma mark - Merging functions for states + +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState hierarchyState, ASEnvironmentStatePropagation propagation) { + // Merge object and hierarchy state + LOG(@"Merge object and state: %@ - ASEnvironmentHierarchyState", object); + return environmentState; +} + +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState layoutOptionsState, ASEnvironmentStatePropagation propagation) { + // Merge object and layout options state + LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", object); + + // Support propagate up + if (propagation == ASEnvironmentStatePropagation::UP) { + + // Object is the parent and the state is the state of the child + const ASEnvironmentLayoutOptionsState defaultState = ASEnvironmentDefaultLayoutOptionsState; + ASEnvironmentLayoutOptionsState parentLayoutOptionsState = environmentState.layoutOptionsState; + + // For every field check if the parent value is equal to the default and if so propegate up the value of the passed + // in layout options state + if (parentLayoutOptionsState.spacingBefore == defaultState.spacingBefore) { + parentLayoutOptionsState.spacingBefore = layoutOptionsState.spacingBefore; + } + if (parentLayoutOptionsState.spacingAfter == defaultState.spacingAfter) { + parentLayoutOptionsState.spacingAfter = layoutOptionsState.spacingAfter; + } + if (parentLayoutOptionsState.alignSelf == defaultState.alignSelf) { + parentLayoutOptionsState.alignSelf = layoutOptionsState.alignSelf; + } + if (parentLayoutOptionsState.flexGrow == defaultState.flexGrow) { + parentLayoutOptionsState.flexGrow = layoutOptionsState.flexGrow; + } + if (ASRelativeDimensionEqualToRelativeDimension(parentLayoutOptionsState.flexBasis, defaultState.flexBasis)) { + parentLayoutOptionsState.flexBasis = layoutOptionsState.flexBasis; + } + if (parentLayoutOptionsState.alignSelf == defaultState.alignSelf) { + parentLayoutOptionsState.alignSelf = layoutOptionsState.alignSelf; + } + if (parentLayoutOptionsState.ascender == defaultState.ascender) { + parentLayoutOptionsState.ascender = layoutOptionsState.ascender; + } + + if (ASRelativeSizeRangeEqualToRelativeSizeRange(parentLayoutOptionsState.sizeRange, defaultState.sizeRange)) { + parentLayoutOptionsState.sizeRange = layoutOptionsState.sizeRange; + } + if (CGPointEqualToPoint(parentLayoutOptionsState.layoutPosition, defaultState.layoutPosition)) { + parentLayoutOptionsState.layoutPosition = layoutOptionsState.layoutPosition; + } + + // Merge extended values if necessary + const ASEnvironmentStateExtensions defaultExtensions = ASEnvironmentDefaultStateExtensions; + const ASEnvironmentStateExtensions layoutOptionsStateExtensions = layoutOptionsState._extensions; + ASEnvironmentStateExtensions parentLayoutOptionsExtensions = parentLayoutOptionsState._extensions; + + for (int i = 0; i < kMaxEnvironmentStateBoolExtensions; i++) { + if (parentLayoutOptionsExtensions.boolExtensions[i] == defaultExtensions.boolExtensions[i]) { + parentLayoutOptionsExtensions.boolExtensions[i] = layoutOptionsStateExtensions.boolExtensions[i]; + } + } + + for (int i = 0; i < kMaxEnvironmentStateIntegerExtensions; i++) { + if (parentLayoutOptionsExtensions.integerExtensions[i] == defaultExtensions.integerExtensions[i]) { + parentLayoutOptionsExtensions.integerExtensions[i] = layoutOptionsStateExtensions.integerExtensions[i]; + } + } + + for (int i = 0; i < kMaxEnvironmentStateEdgeInsetExtensions; i++) { + if (UIEdgeInsetsEqualToEdgeInsets(parentLayoutOptionsExtensions.edgeInsetsExtensions[i], defaultExtensions.edgeInsetsExtensions[i])) { + parentLayoutOptionsExtensions.edgeInsetsExtensions[i] = layoutOptionsStateExtensions.edgeInsetsExtensions[i]; + } + } + parentLayoutOptionsState._extensions = parentLayoutOptionsExtensions; + + // Update layout options state + environmentState.layoutOptionsState = parentLayoutOptionsState; + } + + return environmentState; +} diff --git a/AsyncDisplayKit/Private/ASInternalHelpers.mm b/AsyncDisplayKit/Private/ASInternalHelpers.mm index 0f6aa6f08d..40f6445434 100644 --- a/AsyncDisplayKit/Private/ASInternalHelpers.mm +++ b/AsyncDisplayKit/Private/ASInternalHelpers.mm @@ -34,19 +34,6 @@ BOOL ASSubclassOverridesClassSelector(Class superclass, Class subclass, SEL sele return (superclassIMP != subclassIMP); } -static void ASDispatchOnceOnMainThread(dispatch_once_t *predicate, dispatch_block_t block) -{ - if (ASDisplayNodeThreadIsMain()) { - dispatch_once(predicate, block); - } else { - if (DISPATCH_EXPECT(*predicate == 0L, NO)) { - dispatch_sync(dispatch_get_main_queue(), ^{ - dispatch_once(predicate, block); - }); - } - } -} - void ASPerformBlockOnMainThread(void (^block)()) { if (ASDisplayNodeThreadIsMain()) { @@ -67,12 +54,13 @@ void ASPerformBlockOnBackgroundThread(void (^block)()) CGFloat ASScreenScale() { - static CGFloat _scale; + static CGFloat __scale = 0.0; static dispatch_once_t onceToken; - ASDispatchOnceOnMainThread(&onceToken, ^{ - _scale = [UIScreen mainScreen].scale; + dispatch_once(&onceToken, ^{ + ASDisplayNodeCAssertMainThread(); + __scale = [[UIScreen mainScreen] scale]; }); - return _scale; + return __scale; } CGFloat ASFloorPixelValue(CGFloat f) diff --git a/AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h b/AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h deleted file mode 100644 index 34a26da4f2..0000000000 --- a/AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import -#import -#import - -@interface ASDisplayNode(ASLayoutOptions) -@end - -@interface ASDisplayNode() -{ - ASLayoutOptions *_layoutOptions; - ASDN::RecursiveMutex _layoutOptionsLock; -} -@end - -@interface ASLayoutSpec(ASLayoutOptions) -@end - -@interface ASLayoutSpec() -{ - ASLayoutOptions *_layoutOptions; - ASDN::RecursiveMutex _layoutOptionsLock; -} -@end diff --git a/AsyncDisplayKit/Private/ASMultidimensionalArrayUtils.mm b/AsyncDisplayKit/Private/ASMultidimensionalArrayUtils.mm index ced86ff5d1..f939410d6d 100644 --- a/AsyncDisplayKit/Private/ASMultidimensionalArrayUtils.mm +++ b/AsyncDisplayKit/Private/ASMultidimensionalArrayUtils.mm @@ -44,10 +44,12 @@ static void ASRecursivelyFindIndexPathsForMultidimensionalArray(NSObject *obj, N if (![obj isKindOfClass:[NSArray class]]) { [res addObject:curIndexPath]; } else { - NSArray *arr = (NSArray *)obj; - [arr enumerateObjectsUsingBlock:^(NSObject *subObj, NSUInteger idx, BOOL *stop) { - ASRecursivelyFindIndexPathsForMultidimensionalArray(subObj, [curIndexPath indexPathByAddingIndex:idx], res); - }]; + NSArray *array = (NSArray *)obj; + NSUInteger idx = 0; + for (NSArray *subarray in array) { + ASRecursivelyFindIndexPathsForMultidimensionalArray(subarray, [curIndexPath indexPathByAddingIndex:idx], res); + idx++; + } } } diff --git a/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm b/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm index 28f19ffd77..46df924adf 100644 --- a/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm @@ -12,7 +12,6 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" -#import "ASLayoutOptions.h" static CGFloat baselineForItem(const ASStackLayoutSpecStyle &style, const ASLayout *layout) { @@ -87,7 +86,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A for each node is our computed maxAscender - node.ascender. If the 16pt node had an ascender of 10 and the 14pt node had an ascender of 8, that means we will offset the 14pt node by 2 pts. - Note: if we are alinging to the last baseline, then we don't need this value in our computation. However, we do want + Note: if we are aligning to the last baseline, then we don't need this value in our computation. However, we do want our layoutSpec to have it so that it can be baseline aligned with another text node or baseline layout spec. */ const auto ascenderIt = std::max_element(positionedLayout.sublayouts.begin(), positionedLayout.sublayouts.end(), [&](const ASLayout *a, const ASLayout *b){ @@ -144,7 +143,7 @@ ASStackBaselinePositionedLayout ASStackBaselinePositionedLayout::compute(const A font size of 40 (max ascender). Now, we have to move the node with multiple lines down to the other node's baseline. This node with multiple lines will extend below the first node farther than it did before aligning the baselines thus increasing the cross size. - After finding the new cross size, we need to clamp it so that it fits within the constrainted size. + After finding the new cross size, we need to clamp it so that it fits within the constrained size. */ const auto it = std::max_element(stackedChildren.begin(), stackedChildren.end(), diff --git a/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h b/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h index ae018a1f87..1045bb8501 100644 --- a/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h +++ b/AsyncDisplayKit/Private/ASStackLayoutSpecUtilities.h @@ -72,11 +72,11 @@ inline ASStackLayoutAlignItems alignment(ASStackLayoutAlignSelf childAlignment, inline ASStackLayoutAlignItems alignment(ASHorizontalAlignment alignment, ASStackLayoutAlignItems defaultAlignment) { switch (alignment) { - case ASAlignmentLeft: + case ASHorizontalAlignmentLeft: return ASStackLayoutAlignItemsStart; - case ASAlignmentMiddle: + case ASHorizontalAlignmentMiddle: return ASStackLayoutAlignItemsCenter; - case ASAlignmentRight: + case ASHorizontalAlignmentRight: return ASStackLayoutAlignItemsEnd; case ASHorizontalAlignmentNone: default: @@ -87,11 +87,11 @@ inline ASStackLayoutAlignItems alignment(ASHorizontalAlignment alignment, ASStac inline ASStackLayoutAlignItems alignment(ASVerticalAlignment alignment, ASStackLayoutAlignItems defaultAlignment) { switch (alignment) { - case ASAlignmentTop: + case ASVerticalAlignmentTop: return ASStackLayoutAlignItemsStart; - case ASAlignmentCenter: + case ASVerticalAlignmentCenter: return ASStackLayoutAlignItemsCenter; - case ASAlignmentBottom: + case ASVerticalAlignmentBottom: return ASStackLayoutAlignItemsEnd; case ASVerticalAlignmentNone: default: @@ -102,11 +102,11 @@ inline ASStackLayoutAlignItems alignment(ASVerticalAlignment alignment, ASStackL inline ASStackLayoutJustifyContent justifyContent(ASHorizontalAlignment alignment, ASStackLayoutJustifyContent defaultJustifyContent) { switch (alignment) { - case ASAlignmentLeft: + case ASHorizontalAlignmentLeft: return ASStackLayoutJustifyContentStart; - case ASAlignmentMiddle: + case ASHorizontalAlignmentMiddle: return ASStackLayoutJustifyContentCenter; - case ASAlignmentRight: + case ASHorizontalAlignmentRight: return ASStackLayoutJustifyContentEnd; case ASHorizontalAlignmentNone: default: @@ -117,11 +117,11 @@ inline ASStackLayoutJustifyContent justifyContent(ASHorizontalAlignment alignmen inline ASStackLayoutJustifyContent justifyContent(ASVerticalAlignment alignment, ASStackLayoutJustifyContent defaultJustifyContent) { switch (alignment) { - case ASAlignmentTop: + case ASVerticalAlignmentTop: return ASStackLayoutJustifyContentStart; - case ASAlignmentCenter: + case ASVerticalAlignmentCenter: return ASStackLayoutJustifyContentCenter; - case ASAlignmentBottom: + case ASVerticalAlignmentBottom: return ASStackLayoutJustifyContentEnd; case ASVerticalAlignmentNone: default: diff --git a/AsyncDisplayKit/Private/ASStackPositionedLayout.mm b/AsyncDisplayKit/Private/ASStackPositionedLayout.mm index 428319d317..cd18dd2157 100644 --- a/AsyncDisplayKit/Private/ASStackPositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackPositionedLayout.mm @@ -14,7 +14,6 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" #import "ASLayoutable.h" -#import "ASLayoutOptions.h" #import "ASAssert.h" static CGFloat crossOffset(const ASStackLayoutSpecStyle &style, diff --git a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm index a19ae298ba..57902a6b4e 100644 --- a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm @@ -14,7 +14,6 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" -#import "ASLayoutOptions.h" /** Sizes the child given the parameters specified, and returns the computed layout. @@ -116,8 +115,7 @@ static CGFloat computeStackDimensionSum(const std::vector child = l.child; - const ASLayoutOptions *layoutOptions = child.layoutOptions; - return x + layoutOptions.spacingBefore + layoutOptions.spacingAfter; + return x + child.spacingBefore + child.spacingAfter; }); // Sum up the childrens' dimensions (including spacing) in the stack direction. diff --git a/AsyncDisplayKit/Private/ASWeakSet.m b/AsyncDisplayKit/Private/ASWeakSet.m index 7d8b180080..95c4ad1275 100644 --- a/AsyncDisplayKit/Private/ASWeakSet.m +++ b/AsyncDisplayKit/Private/ASWeakSet.m @@ -46,7 +46,7 @@ // mutable collection is still not safe while enumerating that way - which is one of the main uses for this method. // A helper function called NSAllMapTableKeys() might do exactly what we want and should be more efficient, but unfortunately // is throwing a strange compiler error and may not be available in practice on the latest iOS version. - // Lastly, even -dictionaryRepresentation and then -allKeys won't work, because it attemps to copy the values of each key, + // Lastly, even -dictionaryRepresentation and then -allKeys won't work, because it attempts to copy the values of each key, // which may not support copying (such as ASRangeControllers). NSMutableArray *allObjects = [NSMutableArray array]; for (id object in _mapTable) { diff --git a/AsyncDisplayKit/TextKit/ASTextKitAttributes.h b/AsyncDisplayKit/TextKit/ASTextKitAttributes.h index b765deaca1..49dc9b92f3 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitAttributes.h +++ b/AsyncDisplayKit/TextKit/ASTextKitAttributes.h @@ -8,10 +8,10 @@ * */ -#import +#pragma once -#ifndef ComponentKit_ASTextKitAttributes_h -#define ComponentKit_ASTextKitAttributes_h +#import +#import "ASEqualityHelpers.h" @protocol ASTextKitTruncating; @@ -22,11 +22,6 @@ extern NSString *const ASTextKitTruncationAttributeName; */ extern NSString *const ASTextKitEntityAttributeName; -static inline BOOL _objectsEqual(id obj1, id obj2) -{ - return obj1 == obj2 ? YES : [obj1 isEqual:obj2]; -} - /** All NSObject values in this struct should be copied when passed into the TextComponent. */ @@ -136,14 +131,12 @@ struct ASTextKitAttributes { && layoutManagerCreationBlock == other.layoutManagerCreationBlock && textStorageCreationBlock == other.textStorageCreationBlock && CGSizeEqualToSize(shadowOffset, other.shadowOffset) - && _objectsEqual(exclusionPaths, other.exclusionPaths) - && _objectsEqual(avoidTailTruncationSet, other.avoidTailTruncationSet) - && _objectsEqual(shadowColor, other.shadowColor) - && _objectsEqual(attributedString, other.attributedString) - && _objectsEqual(truncationAttributedString, other.truncationAttributedString); + && ASObjectIsEqual(exclusionPaths, other.exclusionPaths) + && ASObjectIsEqual(avoidTailTruncationSet, other.avoidTailTruncationSet) + && ASObjectIsEqual(shadowColor, other.shadowColor) + && ASObjectIsEqual(attributedString, other.attributedString) + && ASObjectIsEqual(truncationAttributedString, other.truncationAttributedString); } size_t hash() const; }; - -#endif diff --git a/AsyncDisplayKit/TextKit/ASTextKitHelpers.h b/AsyncDisplayKit/TextKit/ASTextKitComponents.h similarity index 66% rename from AsyncDisplayKit/TextKit/ASTextKitHelpers.h rename to AsyncDisplayKit/TextKit/ASTextKitComponents.h index c66b019f96..17f6c1f9cc 100644 --- a/AsyncDisplayKit/TextKit/ASTextKitHelpers.h +++ b/AsyncDisplayKit/TextKit/ASTextKitComponents.h @@ -6,11 +6,8 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import - -#import #import -#import "ASBaseDefines.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -37,8 +34,20 @@ ASDISPLAYNODE_INLINE CGSize ceilSizeValue(CGSize s) @return An `ASTextKitComponents` containing the created components. The text view component will be nil. @discussion The returned components will be hooked up together, so they are ready for use as a system upon return. */ -+ (ASTextKitComponents *)componentsWithAttributedSeedString:(nullable NSAttributedString *)attributedSeedString - textContainerSize:(CGSize)textContainerSize; ++ (instancetype)componentsWithAttributedSeedString:(nullable NSAttributedString *)attributedSeedString + textContainerSize:(CGSize)textContainerSize; + +/** + @abstract Creates the stack of TextKit components. + @param textStorage The NSTextStorage to use. + @param textContainerSize The size of the text-container. Typically, size specifies the constraining width of the layout, and FLT_MAX for height. Pass CGSizeZero if these components will be hooked up to a UITextView, which will manage the text container's size itself. + @param layoutManager The NSLayoutManager to use. + @return An `ASTextKitComponents` containing the created components. The text view component will be nil. + @discussion The returned components will be hooked up together, so they are ready for use as a system upon return. + */ ++ (instancetype)componentsWithTextStorage:(NSTextStorage *)textStorage + textContainerSize:(CGSize)textContainerSize + layoutManager:(NSLayoutManager *)layoutManager; /** @abstract Returns the bounding size for the text view's text. diff --git a/AsyncDisplayKit/TextKit/ASTextKitHelpers.mm b/AsyncDisplayKit/TextKit/ASTextKitComponents.m similarity index 67% rename from AsyncDisplayKit/TextKit/ASTextKitHelpers.mm rename to AsyncDisplayKit/TextKit/ASTextKitComponents.m index 82252b1b7f..4283e3993f 100644 --- a/AsyncDisplayKit/TextKit/ASTextKitHelpers.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitComponents.m @@ -6,7 +6,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import "ASTextKitHelpers.h" +#import "ASTextKitComponents.h" @interface ASTextKitComponents () @@ -19,15 +19,25 @@ @implementation ASTextKitComponents -+ (ASTextKitComponents *)componentsWithAttributedSeedString:(NSAttributedString *)attributedSeedString - textContainerSize:(CGSize)textContainerSize ++ (instancetype)componentsWithAttributedSeedString:(NSAttributedString *)attributedSeedString + textContainerSize:(CGSize)textContainerSize { - ASTextKitComponents *components = [[ASTextKitComponents alloc] init]; + NSTextStorage *textStorage = attributedSeedString ? [[NSTextStorage alloc] initWithAttributedString:attributedSeedString] : [[NSTextStorage alloc] init]; - // Create the TextKit component stack with our default configuration. - components.textStorage = (attributedSeedString ? [[NSTextStorage alloc] initWithAttributedString:attributedSeedString] : [[NSTextStorage alloc] init]); + return [self componentsWithTextStorage:textStorage + textContainerSize:textContainerSize + layoutManager:[[NSLayoutManager alloc] init]]; +} - components.layoutManager = [[NSLayoutManager alloc] init]; ++ (instancetype)componentsWithTextStorage:(NSTextStorage *)textStorage + textContainerSize:(CGSize)textContainerSize + layoutManager:(NSLayoutManager *)layoutManager +{ + ASTextKitComponents *components = [[self alloc] init]; + + components.textStorage = textStorage; + + components.layoutManager = layoutManager; [components.textStorage addLayoutManager:components.layoutManager]; components.textContainer = [[NSTextContainer alloc] initWithSize:textContainerSize]; diff --git a/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.h b/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.h index 9b8ad1ae56..6fe202fa36 100644 --- a/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.h +++ b/AsyncDisplayKit/TextKit/ASTextKitCoreTextAdditions.h @@ -76,7 +76,7 @@ ASDISPLAYNODE_EXTERN_C_END - kCTParagraphStyleSpecifierMinimumLineSpacing - kCTParagraphStyleSpecifierLineSpacingAdjustment - kCTParagraphStyleSpecifierLineBoundsOptions - @result An NSParagraphStyle initializd with as many of the paragraph specifiers from `coreTextParagraphStyle` as possible. + @result An NSParagraphStyle initialized with as many of the paragraph specifiers from `coreTextParagraphStyle` as possible. */ + (instancetype)paragraphStyleWithCTParagraphStyle:(CTParagraphStyleRef)coreTextParagraphStyle; diff --git a/AsyncDisplayKit/TextKit/ASTextKitRenderer.h b/AsyncDisplayKit/TextKit/ASTextKitRenderer.h index 1889131f52..e57c5dc174 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitRenderer.h +++ b/AsyncDisplayKit/TextKit/ASTextKitRenderer.h @@ -58,7 +58,7 @@ @property (nonatomic, assign, readonly) CGFloat currentScaleFactor; #pragma mark - Drawing -/* +/** Draw the renderer's text content into the bounds provided. @param bounds The rect in which to draw the contents of the renderer. @@ -67,20 +67,20 @@ #pragma mark - Layout -/* +/** Returns the computed size of the renderer given the constrained size and other parameters in the initializer. */ - (CGSize)size; #pragma mark - Text Ranges -/* +/** The character range from the original attributedString that is displayed by the renderer given the parameters in the initializer. */ - (std::vector)visibleRanges; -/* +/** The number of lines shown in the string. */ - (NSUInteger)lineCount; diff --git a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm index 84f777e3cd..bc7d2c1069 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm @@ -189,9 +189,10 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet() // We add an assertion so we can track the rare conditions where a graphics context is not present ASDisplayNodeAssertNotNil(context, @"This is no good without a context."); - // This renderer may not be the one that did the sizing. If that is the case its _currentScaleFactor will not be set, so we should compute it now - if (_sizeIsCalculated == NO && isinf(_constrainedSize.width) == NO && [_attributes.pointSizeScaleFactors count] > 0) { - _currentScaleFactor = [[self fontSizeAdjuster] scaleFactor]; + // This renderer may not be the one that did the sizing. If that is the case its truncation and currentScaleFactor may not have been evaluated. + // If there's any possibility we need to truncate or scale (e.g. width is not infinite, perform the size calculation. + if (_sizeIsCalculated == NO && isinf(_constrainedSize.width) == NO) { + [self _calculateSize]; } CGRect shadowInsetBounds = [[self shadower] insetRectWithConstrainedRect:bounds]; diff --git a/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm b/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm index 1ea45e2b91..d48013a772 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm @@ -62,7 +62,7 @@ // We assume LTR so long as the writing direction is not BOOL rtlWritingDirection = paragraphStyle ? paragraphStyle.baseWritingDirection == NSWritingDirectionRightToLeft : NO; - // We only want to treat the trunction rect as left-aligned in the case that we are right-aligned and our writing + // We only want to treat the truncation rect as left-aligned in the case that we are right-aligned and our writing // direction is RTL. BOOL leftAligned = CGRectGetMinX(lastLineRect) == CGRectGetMinX(lastLineUsedRect) || !rtlWritingDirection; diff --git a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm index 10c129f10c..bb38be0d18 100644 --- a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm @@ -13,7 +13,6 @@ #import "ASBackgroundLayoutSpec.h" #import "ASCenterLayoutSpec.h" #import "ASStackLayoutSpec.h" -#import "ASLayoutOptions.h" static const ASSizeRange kSize = {{100, 120}, {320, 160}}; @@ -38,10 +37,14 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; - (void)testWithSizingOptions { - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionDefault]; - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX]; - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY]; - [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionDefault]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY]; + [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone + sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY]; } - (void)testWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)options @@ -51,14 +54,7 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}}; ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); foregroundNode.staticSize = {70, 100}; - ASLayoutSpec *layoutSpec = - [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild: - [ASCenterLayoutSpec - centerLayoutSpecWithCenteringOptions:options - sizingOptions:sizingOptions - child:foregroundNode] - background:backgroundNode]; + ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:[ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:options sizingOptions:sizingOptions child:foregroundNode]background:backgroundNode]; [self testLayoutSpec:layoutSpec sizeRange:kSize @@ -97,14 +93,7 @@ static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions ce foregroundNode.staticSize = {10, 10}; foregroundNode.flexGrow = YES; - ASCenterLayoutSpec *layoutSpec = - [ASCenterLayoutSpec - centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone - sizingOptions:{} - child: - [ASBackgroundLayoutSpec - backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] - background:backgroundNode]]; + ASCenterLayoutSpec *layoutSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:{} child:[ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] background:backgroundNode]]; [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil]; } diff --git a/AsyncDisplayKitTests/ASControlNodeTests.m b/AsyncDisplayKitTests/ASControlNodeTests.m index 969947c3ad..5b094ef0dd 100644 --- a/AsyncDisplayKitTests/ASControlNodeTests.m +++ b/AsyncDisplayKitTests/ASControlNodeTests.m @@ -106,6 +106,76 @@ XCTAssert(controller.hits == 1, @"Controller did not receive the action event"); } +- (void)testRemoveWithoutTargetRemovesTargetlessAction { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node removeTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events"); +} + +- (void)testRemoveWithTarget { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node removeTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events"); +} + +- (void)testRemoveWithTargetRemovesAction { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node removeTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events"); +} + +- (void)testRemoveWithoutTargetRemovesTargetedAction { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node removeTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events"); +} + +- (void)testDuplicateEntriesWithoutTarget { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 1, @"Controller did not receive exactly one action event"); +} + +- (void)testDuplicateEntriesWithTarget { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 1, @"Controller did not receive exactly one action event"); +} + +- (void)testDuplicateEntriesWithAndWithoutTarget { + ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init]; + ASControlNode *node = [[ASControlNode alloc] init]; + [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT]; + [controller.view addSubview:node.view]; + [node sendActionsForControlEvents:EVENT withEvent:nil]; + XCTAssertEqual(controller.hits, 2, @"Controller did not receive exactly two action events"); +} + - (void)testDeeperHierarchyWithoutTarget { ASActionController *controller = [[ASActionController alloc] init]; UIView *view = [[UIView alloc] init]; diff --git a/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm new file mode 100644 index 0000000000..213045ea68 --- /dev/null +++ b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASLayoutSpecSnapshotTestsHelper.h" + +#import "ASBackgroundLayoutSpec.h" +#import "ASRelativeLayoutSpec.h" +#import "ASStackLayoutSpec.h" + +static const ASSizeRange kSize = {{100, 120}, {320, 160}}; + +@interface ASRelativeLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase +@end + +@implementation ASRelativeLayoutSpecSnapshotTests + +- (void)setUp +{ + [super setUp]; + self.recordMode = NO; +} + +- (void)testWithOptions +{ + + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionStart]; + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionCenter]; + [self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionEnd]; + +} + +- (void)testAllVerticalPositionsForHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition { + [self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionStart sizingOptions:{}]; + [self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionCenter sizingOptions:{}]; + [self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionEnd sizingOptions:{}]; +} + +- (void)testWithSizingOptions +{ + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionDefault]; + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumWidth]; + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumHeight]; + [self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart + verticalPosition:ASRelativeLayoutSpecPositionStart + sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumSize]; +} + +- (void)testWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition + verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition + sizingOptions:(ASRelativeLayoutSpecSizingOption)sizingOptions +{ + ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]); + foregroundNode.staticSize = {70, 100}; + + ASLayoutSpec *layoutSpec = + [ASBackgroundLayoutSpec + backgroundLayoutSpecWithChild: + [ASRelativeLayoutSpec + relativePositionLayoutSpecWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:foregroundNode] + background:backgroundNode]; + + [self testLayoutSpec:layoutSpec + sizeRange:kSize + subnodes:@[backgroundNode, foregroundNode] + identifier:suffixForPositionOptions(horizontalPosition, verticalPosition, sizingOptions)]; +} + +static NSString *suffixForPositionOptions(ASRelativeLayoutSpecPosition horizontalPosition, + ASRelativeLayoutSpecPosition verticalPosition, + ASRelativeLayoutSpecSizingOption sizingOptions) +{ + NSMutableString *suffix = [NSMutableString string]; + + if ((horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0) { + [suffix appendString:@"CenterX"]; + } else if ((horizontalPosition & ASRelativeLayoutSpecPositionEnd) != 0) { + [suffix appendString:@"EndX"]; + } + + if ((verticalPosition & ASRelativeLayoutSpecPositionCenter) != 0) { + [suffix appendString:@"CenterY"]; + } else if ((verticalPosition & ASRelativeLayoutSpecPositionEnd) != 0) { + [suffix appendString:@"EndY"]; + } + + if ((sizingOptions & ASRelativeLayoutSpecSizingOptionMinimumWidth) != 0) { + [suffix appendString:@"SizingMinimumWidth"]; + } + + if ((sizingOptions & ASRelativeLayoutSpecSizingOptionMinimumHeight) != 0) { + [suffix appendString:@"SizingMinimumHeight"]; + } + + return suffix; +} + +- (void)testMinimumSizeRangeIsGivenToChildWhenNotPositioning +{ + ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]); + foregroundNode.staticSize = {10, 10}; + foregroundNode.flexGrow = YES; + + ASLayoutSpec *childSpec = [ASBackgroundLayoutSpec + backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] + background:backgroundNode]; + + ASRelativeLayoutSpec *layoutSpec = [ASRelativeLayoutSpec + relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionStart verticalPosition:ASRelativeLayoutSpecPositionStart sizingOption:{} child:childSpec]; + + + [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil]; +} + +@end diff --git a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm index ba98a1f76a..d5ca9074aa 100644 --- a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm @@ -15,7 +15,6 @@ #import "ASBackgroundLayoutSpec.h" #import "ASRatioLayoutSpec.h" #import "ASInsetLayoutSpec.h" -#import "ASLayoutOptions.h" @interface ASStackLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase @end @@ -606,19 +605,19 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) - (void)testHorizontalAndVerticalAlignments { - [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASAlignmentLeft itemsVerticalAlignment:ASAlignmentTop identifier:@"horizontalTopLeft"]; - [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASAlignmentMiddle itemsVerticalAlignment:ASAlignmentCenter identifier:@"horizontalCenter"]; - [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASAlignmentRight itemsVerticalAlignment:ASAlignmentBottom identifier:@"horizontalBottomRight"]; - [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASAlignmentLeft itemsVerticalAlignment:ASAlignmentTop identifier:@"verticalTopLeft"]; - [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASAlignmentMiddle itemsVerticalAlignment:ASAlignmentCenter identifier:@"verticalCenter"]; - [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASAlignmentRight itemsVerticalAlignment:ASAlignmentBottom identifier:@"verticalBottomRight"]; + [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASHorizontalAlignmentLeft itemsVerticalAlignment:ASVerticalAlignmentTop identifier:@"horizontalTopLeft"]; + [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASHorizontalAlignmentMiddle itemsVerticalAlignment:ASVerticalAlignmentCenter identifier:@"horizontalCenter"]; + [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASHorizontalAlignmentRight itemsVerticalAlignment:ASVerticalAlignmentBottom identifier:@"horizontalBottomRight"]; + [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASHorizontalAlignmentLeft itemsVerticalAlignment:ASVerticalAlignmentTop identifier:@"verticalTopLeft"]; + [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASHorizontalAlignmentMiddle itemsVerticalAlignment:ASVerticalAlignmentCenter identifier:@"verticalCenter"]; + [self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASHorizontalAlignmentRight itemsVerticalAlignment:ASVerticalAlignmentBottom identifier:@"verticalBottomRight"]; } - (void)testDirectionChangeAfterSettingHorizontalAndVerticalAlignments { ASStackLayoutSpec *stackLayoutSpec = [[ASStackLayoutSpec alloc] init]; // Default direction is horizontal - stackLayoutSpec.horizontalAlignment = ASAlignmentRight; - stackLayoutSpec.verticalAlignment = ASAlignmentCenter; + stackLayoutSpec.horizontalAlignment = ASHorizontalAlignmentRight; + stackLayoutSpec.verticalAlignment = ASVerticalAlignmentCenter; XCTAssertEqual(stackLayoutSpec.alignItems, ASStackLayoutAlignItemsCenter); XCTAssertEqual(stackLayoutSpec.justifyContent, ASStackLayoutJustifyContentEnd); @@ -636,8 +635,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex) stackLayoutSpec.justifyContent = ASStackLayoutJustifyContentEnd; // Set alignments and assert that assertions are thrown - stackLayoutSpec.horizontalAlignment = ASAlignmentMiddle; - stackLayoutSpec.verticalAlignment = ASAlignmentCenter; + stackLayoutSpec.horizontalAlignment = ASHorizontalAlignmentMiddle; + stackLayoutSpec.verticalAlignment = ASVerticalAlignmentCenter; XCTAssertThrows(stackLayoutSpec.alignItems = ASStackLayoutAlignItemsEnd); XCTAssertThrows(stackLayoutSpec.justifyContent = ASStackLayoutJustifyContentEnd); diff --git a/AsyncDisplayKitTests/ASTableViewTests.m b/AsyncDisplayKitTests/ASTableViewTests.m index 550f3fec9d..2949a16e2f 100644 --- a/AsyncDisplayKitTests/ASTableViewTests.m +++ b/AsyncDisplayKitTests/ASTableViewTests.m @@ -144,18 +144,6 @@ @implementation ASTableViewTests -- (void)setUp -{ - /// Load a display node before the first test. - /// Without this, running this suite specifically - /// (as opposed to all tests) will cause a deadlock - /// because of the dispatch_sync in `ASScreenScale()`. - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - [ASDisplayNode new]; - }); -} - // TODO: Convert this to ARC. - (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate { diff --git a/AsyncDisplayKitTests/ASTextNodeWordKernerTests.mm b/AsyncDisplayKitTests/ASTextNodeWordKernerTests.mm index 6085a88b79..2aba8a3748 100644 --- a/AsyncDisplayKitTests/ASTextNodeWordKernerTests.mm +++ b/AsyncDisplayKitTests/ASTextNodeWordKernerTests.mm @@ -8,7 +8,7 @@ #import -#import "ASTextKitHelpers.h" +#import "ASTextKitComponents.h" #import "ASTextNodeTypes.h" #import "ASTextNodeWordKerner.h" diff --git a/AsyncDisplayKitTests/ASVideoNodeTests.m b/AsyncDisplayKitTests/ASVideoNodeTests.m index 7c663eeca9..de5fe2dd38 100644 --- a/AsyncDisplayKitTests/ASVideoNodeTests.m +++ b/AsyncDisplayKitTests/ASVideoNodeTests.m @@ -8,7 +8,8 @@ #import #import -#import "ASVideoNode.h" +#import +#import @interface ASVideoNodeTests : XCTestCase { @@ -21,6 +22,7 @@ @interface ASVideoNode () { ASDisplayNode *_playerNode; + AVPlayer *_player; } @property (atomic) ASInterfaceState interfaceState; @property (atomic) ASDisplayNode *spinner; @@ -37,6 +39,11 @@ _playerNode = playerNode; } +- (void)setPlayer:(AVPlayer *)player +{ + _player = player; +} + @end @implementation ASVideoNodeTests @@ -189,7 +196,7 @@ - (void)doPlayerLayerNodeIsNotAddedIfVisibleButShouldNotBePlaying { [_videoNode pause]; - [_videoNode setInterfaceState:ASInterfaceStateVisible]; + [_videoNode setInterfaceState:ASInterfaceStateVisible | ASInterfaceStateDisplay]; [_videoNode didLoad]; XCTAssert(![_videoNode.subnodes containsObject:_videoNode.playerNode]); @@ -268,4 +275,23 @@ XCTAssertTrue(_videoNode.shouldBePlaying); } +- (void)testMutingShouldMutePlayer +{ + [_videoNode setPlayer:[[AVPlayer alloc] init]]; + + _videoNode.muted = YES; + + XCTAssertTrue(_videoNode.player.muted); +} + +- (void)testUnMutingShouldUnMutePlayer +{ + [_videoNode setPlayer:[[AVPlayer alloc] init]]; + + _videoNode.muted = YES; + _videoNode.muted = NO; + + XCTAssertFalse(_videoNode.player.muted); +} + @end diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@2x.png new file mode 100644 index 0000000000..02717f8fdb Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions@2x.png new file mode 100644 index 0000000000..50cb613c24 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@2x.png new file mode 100644 index 0000000000..69e7392384 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@2x.png new file mode 100644 index 0000000000..311ef9ed32 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@2x.png new file mode 100644 index 0000000000..385fc3e817 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@2x.png new file mode 100644 index 0000000000..28036afad5 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@2x.png new file mode 100644 index 0000000000..692c2a4e84 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@2x.png new file mode 100644 index 0000000000..04ee2d6115 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@2x.png new file mode 100644 index 0000000000..3d9d16b5d2 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@2x.png new file mode 100644 index 0000000000..7011b35abf Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@2x.png new file mode 100644 index 0000000000..50cb613c24 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@2x.png new file mode 100644 index 0000000000..b14c267b42 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@2x.png new file mode 100644 index 0000000000..270b15feb6 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@2x.png b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@2x.png new file mode 100644 index 0000000000..7fddbff94e Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_32/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@2x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@3x.png new file mode 100644 index 0000000000..3fb6feee42 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testMinimumSizeRangeIsGivenToChildWhenNotPositioning@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions@3x.png new file mode 100644 index 0000000000..c2bf62b078 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@3x.png new file mode 100644 index 0000000000..f1d9c2e52f Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterX@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@3x.png new file mode 100644 index 0000000000..8093c89761 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXCenterY@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@3x.png new file mode 100644 index 0000000000..d9dab946b4 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterXEndY@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@3x.png new file mode 100644 index 0000000000..7e824c2073 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_CenterY@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@3x.png new file mode 100644 index 0000000000..9064f33704 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndX@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@3x.png new file mode 100644 index 0000000000..e634d8e090 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXCenterY@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@3x.png new file mode 100644 index 0000000000..448ad0d27d Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndXEndY@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@3x.png new file mode 100644 index 0000000000..9f88fcc02d Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithOptions_EndY@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@3x.png new file mode 100644 index 0000000000..c2bf62b078 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@3x.png new file mode 100644 index 0000000000..802dbc7bca Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumHeight@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@3x.png new file mode 100644 index 0000000000..6796058c28 Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidth@3x.png differ diff --git a/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@3x.png b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@3x.png new file mode 100644 index 0000000000..d4a15f979b Binary files /dev/null and b/AsyncDisplayKitTests/ReferenceImages_64/ASRelativeLayoutSpecSnapshotTests/testWithSizingOptions_SizingMinimumWidthSizingMinimumHeight@3x.png differ diff --git a/Base/ASAssert.h b/Base/ASAssert.h index b0b53cc855..446f64b4b7 100644 --- a/Base/ASAssert.h +++ b/Base/ASAssert.h @@ -9,6 +9,7 @@ #pragma once #import +#import #define ASDisplayNodeAssertWithSignalAndLogFunction(condition, description, logFunction, ...) NSAssert(condition, description, ##__VA_ARGS__); #define ASDisplayNodeCAssertWithSignalAndLogFunction(condition, description, logFunction, ...) NSCAssert(condition, description, ##__VA_ARGS__); @@ -30,11 +31,11 @@ #define ASDisplayNodeAssertNotInstantiable() ASDisplayNodeAssertWithSignal(NO, nil, @"This class is not instantiable."); #define ASDisplayNodeAssertNotSupported() ASDisplayNodeAssertWithSignal(NO, nil, @"This method is not supported by class %@", [self class]); -#define ASDisplayNodeAssertMainThread() ASDisplayNodeAssertWithSignal([NSThread isMainThread], nil, @"This method must be called on the main thread") -#define ASDisplayNodeCAssertMainThread() ASDisplayNodeCAssertWithSignal([NSThread isMainThread], nil, @"This function must be called on the main thread") +#define ASDisplayNodeAssertMainThread() ASDisplayNodeAssertWithSignal(0 != pthread_main_np(), nil, @"This method must be called on the main thread") +#define ASDisplayNodeCAssertMainThread() ASDisplayNodeCAssertWithSignal(0 != pthread_main_np(), nil, @"This function must be called on the main thread") -#define ASDisplayNodeAssertNotMainThread() ASDisplayNodeAssertWithSignal(![NSThread isMainThread], nil, @"This method must be called off the main thread") -#define ASDisplayNodeCAssertNotMainThread() ASDisplayNodeCAssertWithSignal(![NSThread isMainThread], nil, @"This function must be called off the main thread") +#define ASDisplayNodeAssertNotMainThread() ASDisplayNodeAssertWithSignal(0 == pthread_main_np(), nil, @"This method must be called off the main thread") +#define ASDisplayNodeCAssertNotMainThread() ASDisplayNodeCAssertWithSignal(0 == pthread_main_np(), nil, @"This function must be called off the main thread") #define ASDisplayNodeAssertFlag(X) ASDisplayNodeAssertWithSignal((1 == __builtin_popcount(X)), nil, nil) #define ASDisplayNodeCAssertFlag(X) ASDisplayNodeCAssertWithSignal((1 == __builtin_popcount(X)), nil, nil) diff --git a/Base/ASEqualityHelpers.h b/Base/ASEqualityHelpers.h index e4447aef0c..f6dd4de1b7 100644 --- a/Base/ASEqualityHelpers.h +++ b/Base/ASEqualityHelpers.h @@ -16,7 +16,5 @@ */ ASDISPLAYNODE_INLINE BOOL ASObjectIsEqual(id obj, id otherObj) { - if (obj == otherObj) - return YES; - return [obj isEqual:otherObj]; + return obj == otherObj || [obj isEqual:otherObj]; } diff --git a/README.md b/README.md index 68c98c516b..82be85be80 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ [![Coverage Status](https://coveralls.io/repos/facebook/AsyncDisplayKit/badge.svg?branch=master)](https://coveralls.io/r/facebook/AsyncDisplayKit?branch=master) [![Version](https://img.shields.io/cocoapods/v/AsyncDisplayKit.svg)](http://cocoapods.org/pods/AsyncDisplayKit) [![Platform](https://img.shields.io/cocoapods/p/AsyncDisplayKit.svg)]() +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![License](https://img.shields.io/cocoapods/l/AsyncDisplayKit.svg)](https://github.com/facebook/AsyncDisplayKit/blob/master/LICENSE) -[![Downloads](https://img.shields.io/badge/downloads-%3E120k-green.svg)](http://cocoapods.org/pods/AsyncDisplayKit) +[![Downloads](https://img.shields.io/badge/downloads-%3E320k-green.svg)](http://cocoapods.org/pods/AsyncDisplayKit) AsyncDisplayKit is an iOS framework that keeps even the most complex user interfaces smooth and responsive. It was originally built to make Facebook's diff --git a/build.sh b/build.sh index d2f19504d3..c3744eab05 100755 --- a/build.sh +++ b/build.sh @@ -1,8 +1,8 @@ #!/bin/bash # **** Update me when new Xcode versions are released! **** -PLATFORM="platform=iOS Simulator,OS=9.2,name=iPhone 6" -SDK="iphonesimulator9.2" +PLATFORM="platform=iOS Simulator,OS=9.3,name=iPhone 6" +SDK="iphonesimulator9.3" # It is pitch black. @@ -35,13 +35,35 @@ if [ "$MODE" = "examples" ]; then for example in examples/*/; do echo "Building $example." - pod install --project-directory=$example - xctool \ - -workspace "${example}Sample.xcworkspace" \ - -scheme Sample \ - -sdk "$SDK" \ - -destination "$PLATFORM" \ - build + + if [ -f "${example}/Podfile" ]; then + echo "Using CocoaPods" + pod install --project-directory=$example + + xctool \ + -workspace "${example}Sample.xcworkspace" \ + -scheme Sample \ + -sdk "$SDK" \ + -destination "$PLATFORM" \ + build + elif [ -f "${example}/Cartfile" ]; then + echo "Using Carthage" + local_repo=`pwd` + current_branch=`git rev-parse --abbrev-ref HEAD` + cd $example + + echo "git \"file://${local_repo}\" \"${current_branch}\"" > "Cartfile" + carthage update --platform iOS + + xctool \ + -project "Sample.xcodeproj" \ + -scheme Sample \ + -sdk "$SDK" \ + -destination "$PLATFORM" \ + build + + cd ../.. + fi done trap - EXIT exit 0 diff --git a/examples/ASViewController/Podfile b/examples/ASViewController/Podfile index 6c012e3c04..840a147de4 100644 --- a/examples/ASViewController/Podfile +++ b/examples/ASViewController/Podfile @@ -1,3 +1,3 @@ source 'https://github.com/CocoaPods/Specs.git' -platform :ios, '8.0' +platform :ios, '7.1' pod 'AsyncDisplayKit', :path => '../..' diff --git a/examples/ASViewController/Sample/AppDelegate.m b/examples/ASViewController/Sample/AppDelegate.m index 52ce975a1b..82398fb14a 100644 --- a/examples/ASViewController/Sample/AppDelegate.m +++ b/examples/ASViewController/Sample/AppDelegate.m @@ -18,7 +18,6 @@ @implementation AppDelegate - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; @@ -28,26 +27,4 @@ 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/ASViewController/Sample/DetailCellNode.m b/examples/ASViewController/Sample/DetailCellNode.m index 825bb657ac..a5e99653ea 100644 --- a/examples/ASViewController/Sample/DetailCellNode.m +++ b/examples/ASViewController/Sample/DetailCellNode.m @@ -21,32 +21,33 @@ self = [super init]; if (self == nil) { return self; } - _imageNode = [ASNetworkImageNode new]; + _imageNode = [[ASNetworkImageNode alloc] init]; _imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); [self addSubnode:_imageNode]; return self; } - #pragma mark - ASDisplayNode - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - ASStaticLayoutSpec *staticSpec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.imageNode]]; self.imageNode.position = CGPointZero; self.imageNode.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); - return staticSpec; + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.imageNode]]; } -- (void)fetchData +- (void)layoutDidFinish { - [super fetchData]; + [super layoutDidFinish]; - [self loadImage]; + // In general set URL of ASNetworkImageNode as soon as possible. Ideally in init or a + // view model setter method. + // In this case as we need to know the size of the node the url is set in layoutDidFinish so + // we have the calculatedSize available + self.imageNode.URL = [self imageURL]; } - #pragma mark - Image - (NSURL *)imageURL @@ -56,9 +57,4 @@ return [NSURL URLWithString:imageURLString]; } -- (void)loadImage -{ - self.imageNode.URL = self.imageURL; -} - @end diff --git a/examples/ASViewController/Sample/DetailRootNode.m b/examples/ASViewController/Sample/DetailRootNode.m index 5aa17f31b5..7dec4b9534 100644 --- a/examples/ASViewController/Sample/DetailRootNode.m +++ b/examples/ASViewController/Sample/DetailRootNode.m @@ -31,38 +31,37 @@ static const NSInteger kImageHeight = 200; if (self == nil) { return self; } _imageCategory = imageCategory; - [self initNode]; - - return self; -} -- (void)initNode -{ // Create ASCollectionView. We don't have to add it explicitly as subnode as we will set usesImplicitHierarchyManagement to YES UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; _collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout]; _collectionNode.delegate = self; _collectionNode.dataSource = self; - _collectionNode.view.backgroundColor = [UIColor whiteColor]; + _collectionNode.backgroundColor = [UIColor whiteColor]; // Enable usesImplicitHierarchyManagement so the first time the layout pass of the node is happening all nodes that are referenced // in layouts within layoutSpecThatFits: will be added automatically self.usesImplicitHierarchyManagement = YES; + + return self; } +- (void)dealloc +{ + _collectionNode.delegate = nil; + _collectionNode.dataSource = nil; +} -#pragma mark - +#pragma mark - ASDisplayNode - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - ASStaticLayoutSpec *staticSpec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.collectionNode]]; self.collectionNode.position = CGPointZero; self.collectionNode.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(constrainedSize.max); - return staticSpec; + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[self.collectionNode]]; } - -#pragma mark - +#pragma mark - ASCollectionDataSource - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { @@ -73,7 +72,7 @@ static const NSInteger kImageHeight = 200; { NSString *imageCategory = self.imageCategory; return ^{ - DetailCellNode *node = [DetailCellNode new]; + DetailCellNode *node = [[DetailCellNode alloc] init]; node.row = indexPath.row; node.imageCategory = imageCategory; return node; diff --git a/examples/ASViewController/Sample/DetailViewController.m b/examples/ASViewController/Sample/DetailViewController.m index 78a28fd3a6..9a6577eb0b 100644 --- a/examples/ASViewController/Sample/DetailViewController.m +++ b/examples/ASViewController/Sample/DetailViewController.m @@ -21,7 +21,7 @@ - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - [self.node.collectionNode.view invalidateIntrinsicContentSize]; + [self.node.collectionNode.view.collectionViewLayout invalidateLayout]; } @end diff --git a/examples/CarthageBuildTest/Cartfile b/examples/CarthageBuildTest/Cartfile new file mode 100644 index 0000000000..75ef551216 --- /dev/null +++ b/examples/CarthageBuildTest/Cartfile @@ -0,0 +1 @@ +git "file:///build.sh/will/put/local/absolute/path/here" "master" diff --git a/examples/CarthageBuildTest/CarthageExample/AppDelegate.h b/examples/CarthageBuildTest/CarthageExample/AppDelegate.h new file mode 100644 index 0000000000..6f3bc417f3 --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// CarthageExample +// +// Created by Engin Kurutepe on 23/02/16. +// Copyright © 2016 Engin Kurutepe. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/examples/CarthageBuildTest/CarthageExample/AppDelegate.m b/examples/CarthageBuildTest/CarthageExample/AppDelegate.m new file mode 100644 index 0000000000..225a9f70b1 --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/AppDelegate.m @@ -0,0 +1,47 @@ +// +// AppDelegate.m +// CarthageExample +// +// Created by Engin Kurutepe on 23/02/16. +// Copyright © 2016 Engin Kurutepe. All rights reserved. +// + +@import AsyncDisplayKit; + +#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/CarthageBuildTest/CarthageExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/CarthageBuildTest/CarthageExample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..118c98f746 --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "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" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/CarthageBuildTest/CarthageExample/Base.lproj/LaunchScreen.storyboard b/examples/CarthageBuildTest/CarthageExample/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..2e721e1833 --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CarthageBuildTest/CarthageExample/Base.lproj/Main.storyboard b/examples/CarthageBuildTest/CarthageExample/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..f56d2f3bb5 --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CarthageBuildTest/CarthageExample/Info.plist b/examples/CarthageBuildTest/CarthageExample/Info.plist new file mode 100644 index 0000000000..6905cc67bb --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/Info.plist @@ -0,0 +1,40 @@ + + + + + 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 + + + diff --git a/examples/CarthageBuildTest/CarthageExample/ViewController.h b/examples/CarthageBuildTest/CarthageExample/ViewController.h new file mode 100644 index 0000000000..4cf7ecbc3e --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// CarthageExample +// +// Created by Engin Kurutepe on 23/02/16. +// Copyright © 2016 Engin Kurutepe. All rights reserved. +// + +#import + +@interface ViewController : UIViewController + + +@end + diff --git a/examples/CarthageBuildTest/CarthageExample/ViewController.m b/examples/CarthageBuildTest/CarthageExample/ViewController.m new file mode 100644 index 0000000000..a65c7f7d6e --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/ViewController.m @@ -0,0 +1,36 @@ +// +// ViewController.m +// CarthageExample +// +// Created by Engin Kurutepe on 23/02/16. +// Copyright © 2016 Engin Kurutepe. All rights reserved. +// + +@import AsyncDisplayKit; + +#import "ViewController.h" + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + CGSize screenSize = self.view.bounds.size; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + ASTextNode *node = [[ASTextNode alloc] init]; + node.attributedString = [[NSAttributedString alloc] initWithString:@"hello world"]; + [node measure:(CGSize){.width = screenSize.width, .height = CGFLOAT_MAX}]; + node.frame = (CGRect) {.origin = (CGPoint){.x = 100, .y = 100}, .size = node.calculatedSize }; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.view addSubview:node.view]; + }); + }); +} + +@end diff --git a/examples/CarthageBuildTest/CarthageExample/main.m b/examples/CarthageBuildTest/CarthageExample/main.m new file mode 100644 index 0000000000..e37b278758 --- /dev/null +++ b/examples/CarthageBuildTest/CarthageExample/main.m @@ -0,0 +1,16 @@ +// +// main.m +// CarthageExample +// +// Created by Engin Kurutepe on 23/02/16. +// Copyright © 2016 Engin Kurutepe. 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/CarthageBuildTest/README.md b/examples/CarthageBuildTest/README.md new file mode 100644 index 0000000000..65ad6a6737 --- /dev/null +++ b/examples/CarthageBuildTest/README.md @@ -0,0 +1,7 @@ +This project is supposed to test that the `AsyncDisplayKit.framework` built by Carthage from the master branch can be imported as a module without causing any warnings and errors. + +Steps to verify: + +- Run `carthage update --platform iOS` +- Build `CarthageExample.xcodeproj` +- Verify that there are 0 Errors and 0 Warnings diff --git a/examples/CarthageBuildTest/Sample.xcodeproj/project.pbxproj b/examples/CarthageBuildTest/Sample.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..cffd86f348 --- /dev/null +++ b/examples/CarthageBuildTest/Sample.xcodeproj/project.pbxproj @@ -0,0 +1,349 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 871BB34E1C7C98B1005CF62A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 871BB34D1C7C98B1005CF62A /* main.m */; }; + 871BB3511C7C98B1005CF62A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 871BB3501C7C98B1005CF62A /* AppDelegate.m */; }; + 871BB3541C7C98B1005CF62A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 871BB3531C7C98B1005CF62A /* ViewController.m */; }; + 871BB3571C7C98B1005CF62A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 871BB3551C7C98B1005CF62A /* Main.storyboard */; }; + 871BB3591C7C98B1005CF62A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 871BB3581C7C98B1005CF62A /* Assets.xcassets */; }; + 871BB35C1C7C98B1005CF62A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 871BB35A1C7C98B1005CF62A /* LaunchScreen.storyboard */; }; + 871BB3651C7C99B0005CF62A /* AsyncDisplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 871BB3641C7C99B0005CF62A /* AsyncDisplayKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 871BB3491C7C98B1005CF62A /* CarthageExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CarthageExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 871BB34D1C7C98B1005CF62A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 871BB34F1C7C98B1005CF62A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 871BB3501C7C98B1005CF62A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 871BB3521C7C98B1005CF62A /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 871BB3531C7C98B1005CF62A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 871BB3561C7C98B1005CF62A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 871BB3581C7C98B1005CF62A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 871BB35B1C7C98B1005CF62A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 871BB35D1C7C98B1005CF62A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 871BB3641C7C99B0005CF62A /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AsyncDisplayKit.framework; path = Carthage/Build/iOS/AsyncDisplayKit.framework; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 871BB3461C7C98B1005CF62A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 871BB3651C7C99B0005CF62A /* AsyncDisplayKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 871BB3401C7C98B1005CF62A = { + isa = PBXGroup; + children = ( + 871BB34B1C7C98B1005CF62A /* CarthageExample */, + 871BB34A1C7C98B1005CF62A /* Products */, + ); + sourceTree = ""; + }; + 871BB34A1C7C98B1005CF62A /* Products */ = { + isa = PBXGroup; + children = ( + 871BB3491C7C98B1005CF62A /* CarthageExample.app */, + ); + name = Products; + sourceTree = ""; + }; + 871BB34B1C7C98B1005CF62A /* CarthageExample */ = { + isa = PBXGroup; + children = ( + 871BB34F1C7C98B1005CF62A /* AppDelegate.h */, + 871BB3501C7C98B1005CF62A /* AppDelegate.m */, + 871BB3581C7C98B1005CF62A /* Assets.xcassets */, + 871BB3631C7C9994005CF62A /* Frameworks */, + 871BB35D1C7C98B1005CF62A /* Info.plist */, + 871BB35A1C7C98B1005CF62A /* LaunchScreen.storyboard */, + 871BB3551C7C98B1005CF62A /* Main.storyboard */, + 871BB34C1C7C98B1005CF62A /* Supporting Files */, + 871BB3521C7C98B1005CF62A /* ViewController.h */, + 871BB3531C7C98B1005CF62A /* ViewController.m */, + ); + path = CarthageExample; + sourceTree = ""; + }; + 871BB34C1C7C98B1005CF62A /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 871BB34D1C7C98B1005CF62A /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 871BB3631C7C9994005CF62A /* Frameworks */ = { + isa = PBXGroup; + children = ( + 871BB3641C7C99B0005CF62A /* AsyncDisplayKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 871BB3481C7C98B1005CF62A /* CarthageExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 871BB3601C7C98B1005CF62A /* Build configuration list for PBXNativeTarget "CarthageExample" */; + buildPhases = ( + 871BB3451C7C98B1005CF62A /* Sources */, + 871BB3461C7C98B1005CF62A /* Frameworks */, + 871BB3471C7C98B1005CF62A /* Resources */, + 871BB3661C7C99B8005CF62A /* Copy Framworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CarthageExample; + productName = CarthageExample; + productReference = 871BB3491C7C98B1005CF62A /* CarthageExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 871BB3411C7C98B1005CF62A /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Engin Kurutepe"; + TargetAttributes = { + 871BB3481C7C98B1005CF62A = { + CreatedOnToolsVersion = 7.2.1; + }; + }; + }; + buildConfigurationList = 871BB3441C7C98B1005CF62A /* Build configuration list for PBXProject "CarthageExample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 871BB3401C7C98B1005CF62A; + productRefGroup = 871BB34A1C7C98B1005CF62A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 871BB3481C7C98B1005CF62A /* CarthageExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 871BB3471C7C98B1005CF62A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 871BB35C1C7C98B1005CF62A /* LaunchScreen.storyboard in Resources */, + 871BB3591C7C98B1005CF62A /* Assets.xcassets in Resources */, + 871BB3571C7C98B1005CF62A /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 871BB3661C7C99B8005CF62A /* Copy Framworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/AsyncDisplayKit.framework", + ); + name = "Copy Framworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 871BB3451C7C98B1005CF62A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 871BB3541C7C98B1005CF62A /* ViewController.m in Sources */, + 871BB3511C7C98B1005CF62A /* AppDelegate.m in Sources */, + 871BB34E1C7C98B1005CF62A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 871BB3551C7C98B1005CF62A /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 871BB3561C7C98B1005CF62A /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 871BB35A1C7C98B1005CF62A /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 871BB35B1C7C98B1005CF62A /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 871BB35E1C7C98B1005CF62A /* 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; + }; + name = Debug; + }; + 871BB35F1C7C98B1005CF62A /* 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; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 871BB3611C7C98B1005CF62A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + INFOPLIST_FILE = CarthageExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.asyncdisplaykit.CarthageExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 871BB3621C7C98B1005CF62A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + INFOPLIST_FILE = CarthageExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.asyncdisplaykit.CarthageExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 871BB3441C7C98B1005CF62A /* Build configuration list for PBXProject "CarthageExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 871BB35E1C7C98B1005CF62A /* Debug */, + 871BB35F1C7C98B1005CF62A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 871BB3601C7C98B1005CF62A /* Build configuration list for PBXNativeTarget "CarthageExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 871BB3611C7C98B1005CF62A /* Debug */, + 871BB3621C7C98B1005CF62A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 871BB3411C7C98B1005CF62A /* Project object */; +} diff --git a/examples/CarthageBuildTest/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/CarthageBuildTest/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..ef35de35d9 --- /dev/null +++ b/examples/CarthageBuildTest/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/CarthageBuildTest/Sample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/examples/CarthageBuildTest/Sample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..08de0be8d3 --- /dev/null +++ b/examples/CarthageBuildTest/Sample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/examples/CarthageBuildTest/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/examples/CarthageBuildTest/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme new file mode 100644 index 0000000000..8b3132f292 --- /dev/null +++ b/examples/CarthageBuildTest/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CustomCollectionView/Sample/MosaicCollectionViewLayout.m b/examples/CustomCollectionView/Sample/MosaicCollectionViewLayout.m index 0e2c65d027..67654b0df9 100644 --- a/examples/CustomCollectionView/Sample/MosaicCollectionViewLayout.m +++ b/examples/CustomCollectionView/Sample/MosaicCollectionViewLayout.m @@ -119,7 +119,7 @@ - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { - if (!CGRectEqualToRect(self.collectionView.bounds, newBounds)) { + if (!CGSizeEqualToSize(self.collectionView.bounds.size, newBounds.size)) { return YES; } return NO; diff --git a/examples/EditableText/CustomCollectionView.gif b/examples/EditableText/CustomCollectionView.gif new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/EditableText/Sample.xcodeproj/project.pbxproj b/examples/EditableText/Sample.xcodeproj/project.pbxproj index a1a1bd3d35..3440a43995 100644 --- a/examples/EditableText/Sample.xcodeproj/project.pbxproj +++ b/examples/EditableText/Sample.xcodeproj/project.pbxproj @@ -1,345 +1,726 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */; }; - 05E2128719D4DB510098F589 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128619D4DB510098F589 /* main.m */; }; - 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128919D4DB510098F589 /* AppDelegate.m */; }; - 05E2128D19D4DB510098F589 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128C19D4DB510098F589 /* ViewController.m */; }; - 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */; }; - 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AA19EE274300767484 /* Default-667h@2x.png */; }; - 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AB19EE274300767484 /* Default-736h@3x.png */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = ""; }; - 05E2128119D4DB510098F589 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 05E2128519D4DB510098F589 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 05E2128619D4DB510098F589 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 05E2128819D4DB510098F589 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 05E2128919D4DB510098F589 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 05E2128B19D4DB510098F589 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - 05E2128C19D4DB510098F589 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; - 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 6C2C82AA19EE274300767484 /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; }; - 6C2C82AB19EE274300767484 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; }; - C068F1D3F0CC317E895FCDAB /* 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 */ - 05E2127E19D4DB510098F589 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 05E2127819D4DB510098F589 = { - isa = PBXGroup; - children = ( - 05E2128319D4DB510098F589 /* Sample */, - 05E2128219D4DB510098F589 /* Products */, - 1A943BF0259746F18D6E423F /* Frameworks */, - 1AE410B73DA5C3BD087ACDD7 /* Pods */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - usesTabs = 0; - }; - 05E2128219D4DB510098F589 /* Products */ = { - isa = PBXGroup; - children = ( - 05E2128119D4DB510098F589 /* Sample.app */, - ); - name = Products; - sourceTree = ""; - }; - 05E2128319D4DB510098F589 /* Sample */ = { - isa = PBXGroup; - children = ( - 05E2128819D4DB510098F589 /* AppDelegate.h */, - 05E2128919D4DB510098F589 /* AppDelegate.m */, - 05E2128B19D4DB510098F589 /* ViewController.h */, - 05E2128C19D4DB510098F589 /* ViewController.m */, - 05E2128419D4DB510098F589 /* Supporting Files */, - ); - path = Sample; - sourceTree = ""; - }; - 05E2128419D4DB510098F589 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */, - 6C2C82AA19EE274300767484 /* Default-667h@2x.png */, - 6C2C82AB19EE274300767484 /* Default-736h@3x.png */, - 05E2128519D4DB510098F589 /* Info.plist */, - 05E2128619D4DB510098F589 /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 1A943BF0259746F18D6E423F /* Frameworks */ = { - isa = PBXGroup; - children = ( - 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */, - ); - name = Frameworks; - sourceTree = ""; - }; - 1AE410B73DA5C3BD087ACDD7 /* Pods */ = { - isa = PBXGroup; - children = ( - C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */, - 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 05E2128019D4DB510098F589 /* Sample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */; - buildPhases = ( - E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */, - 05E2127D19D4DB510098F589 /* Sources */, - 05E2127E19D4DB510098F589 /* Frameworks */, - 05E2127F19D4DB510098F589 /* Resources */, - F012A6F39E0149F18F564F50 /* Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Sample; - productName = Sample; - productReference = 05E2128119D4DB510098F589 /* Sample.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 05E2127919D4DB510098F589 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0600; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 05E2128019D4DB510098F589 = { - CreatedOnToolsVersion = 6.0.1; - }; - }; - }; - buildConfigurationList = 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 05E2127819D4DB510098F589; - productRefGroup = 05E2128219D4DB510098F589 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 05E2128019D4DB510098F589 /* Sample */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 05E2127F19D4DB510098F589 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */, - 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */, - 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - E080B80F89C34A25B3488E26 /* 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; - }; - F012A6F39E0149F18F564F50 /* 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; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 05E2127D19D4DB510098F589 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 05E2128D19D4DB510098F589 /* ViewController.m in Sources */, - 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */, - 05E2128719D4DB510098F589 /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 05E212A219D4DB510098F589 /* 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; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - 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.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 05E212A319D4DB510098F589 /* 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 = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - 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.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 05E212A519D4DB510098F589 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Sample/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 05E212A619D4DB510098F589 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Sample/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 05E212A219D4DB510098F589 /* Debug */, - 05E212A319D4DB510098F589 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 05E212A519D4DB510098F589 /* Debug */, - 05E212A619D4DB510098F589 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 05E2127919D4DB510098F589 /* Project object */; -} + + + + + archiveVersion + 1 + classes + + objectVersion + 46 + objects + + 0585427F19D4DBE100606EA6 + + isa + PBXFileReference + lastKnownFileType + image.png + name + Default-568h@2x.png + path + ../Default-568h@2x.png + sourceTree + <group> + + 0585428019D4DBE100606EA6 + + fileRef + 0585427F19D4DBE100606EA6 + isa + PBXBuildFile + + 05E2127819D4DB510098F589 + + children + + 05E2128319D4DB510098F589 + 05E2128219D4DB510098F589 + 1A943BF0259746F18D6E423F + 1AE410B73DA5C3BD087ACDD7 + + indentWidth + 2 + isa + PBXGroup + sourceTree + <group> + tabWidth + 2 + usesTabs + 0 + + 05E2127919D4DB510098F589 + + attributes + + LastUpgradeCheck + 0600 + ORGANIZATIONNAME + Facebook + TargetAttributes + + 05E2128019D4DB510098F589 + + CreatedOnToolsVersion + 6.0.1 + + + + buildConfigurationList + 05E2127C19D4DB510098F589 + compatibilityVersion + Xcode 3.2 + developmentRegion + English + hasScannedForEncodings + 0 + isa + PBXProject + knownRegions + + en + Base + + mainGroup + 05E2127819D4DB510098F589 + productRefGroup + 05E2128219D4DB510098F589 + projectDirPath + + projectReferences + + projectRoot + + targets + + 05E2128019D4DB510098F589 + + + 05E2127C19D4DB510098F589 + + buildConfigurations + + 05E212A219D4DB510098F589 + 05E212A319D4DB510098F589 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 05E2127D19D4DB510098F589 + + buildActionMask + 2147483647 + files + + 05E2128D19D4DB510098F589 + 05E2128A19D4DB510098F589 + 05E2128719D4DB510098F589 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 05E2127E19D4DB510098F589 + + buildActionMask + 2147483647 + files + + 3EC0CDCBA10D483D9F386E5E + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 05E2127F19D4DB510098F589 + + buildActionMask + 2147483647 + files + + 0585428019D4DBE100606EA6 + 6C2C82AC19EE274300767484 + 6C2C82AD19EE274300767484 + + isa + PBXResourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 05E2128019D4DB510098F589 + + buildConfigurationList + 05E212A419D4DB510098F589 + buildPhases + + E080B80F89C34A25B3488E26 + 05E2127D19D4DB510098F589 + 05E2127E19D4DB510098F589 + 05E2127F19D4DB510098F589 + F012A6F39E0149F18F564F50 + 6FBCCC34F8CCA9B610492536 + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Sample + productName + Sample + productReference + 05E2128119D4DB510098F589 + productType + com.apple.product-type.application + + 05E2128119D4DB510098F589 + + explicitFileType + wrapper.application + includeInIndex + 0 + isa + PBXFileReference + path + Sample.app + sourceTree + BUILT_PRODUCTS_DIR + + 05E2128219D4DB510098F589 + + children + + 05E2128119D4DB510098F589 + + isa + PBXGroup + name + Products + sourceTree + <group> + + 05E2128319D4DB510098F589 + + children + + 05E2128819D4DB510098F589 + 05E2128919D4DB510098F589 + 05E2128B19D4DB510098F589 + 05E2128C19D4DB510098F589 + 05E2128419D4DB510098F589 + + isa + PBXGroup + path + Sample + sourceTree + <group> + + 05E2128419D4DB510098F589 + + children + + 0585427F19D4DBE100606EA6 + 6C2C82AA19EE274300767484 + 6C2C82AB19EE274300767484 + 05E2128519D4DB510098F589 + 05E2128619D4DB510098F589 + + isa + PBXGroup + name + Supporting Files + sourceTree + <group> + + 05E2128519D4DB510098F589 + + isa + PBXFileReference + lastKnownFileType + text.plist.xml + path + Info.plist + sourceTree + <group> + + 05E2128619D4DB510098F589 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + main.m + sourceTree + <group> + + 05E2128719D4DB510098F589 + + fileRef + 05E2128619D4DB510098F589 + isa + PBXBuildFile + + 05E2128819D4DB510098F589 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + AppDelegate.h + sourceTree + <group> + + 05E2128919D4DB510098F589 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + AppDelegate.m + sourceTree + <group> + + 05E2128A19D4DB510098F589 + + fileRef + 05E2128919D4DB510098F589 + isa + PBXBuildFile + + 05E2128B19D4DB510098F589 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + ViewController.h + sourceTree + <group> + + 05E2128C19D4DB510098F589 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + ViewController.m + sourceTree + <group> + + 05E2128D19D4DB510098F589 + + fileRef + 05E2128C19D4DB510098F589 + isa + PBXBuildFile + + 05E212A219D4DB510098F589 + + 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 + ENABLE_STRICT_OBJC_MSGSEND + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_DYNAMIC_NO_PIC + NO + 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.0 + MTL_ENABLE_DEBUG_INFO + YES + ONLY_ACTIVE_ARCH + YES + SDKROOT + iphoneos + + isa + XCBuildConfiguration + name + Debug + + 05E212A319D4DB510098F589 + + 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 + YES + ENABLE_NS_ASSERTIONS + NO + ENABLE_STRICT_OBJC_MSGSEND + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + 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.0 + MTL_ENABLE_DEBUG_INFO + NO + SDKROOT + iphoneos + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 05E212A419D4DB510098F589 + + buildConfigurations + + 05E212A519D4DB510098F589 + 05E212A619D4DB510098F589 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 05E212A519D4DB510098F589 + + baseConfigurationReference + C068F1D3F0CC317E895FCDAB + buildSettings + + ASSETCATALOG_COMPILER_APPICON_NAME + AppIcon + INFOPLIST_FILE + Sample/Info.plist + LD_RUNPATH_SEARCH_PATHS + $(inherited) @executable_path/Frameworks + PRODUCT_NAME + $(TARGET_NAME) + + isa + XCBuildConfiguration + name + Debug + + 05E212A619D4DB510098F589 + + baseConfigurationReference + 088AA6578212BE9BFBB07B70 + buildSettings + + ASSETCATALOG_COMPILER_APPICON_NAME + AppIcon + INFOPLIST_FILE + Sample/Info.plist + LD_RUNPATH_SEARCH_PATHS + $(inherited) @executable_path/Frameworks + PRODUCT_NAME + $(TARGET_NAME) + + isa + XCBuildConfiguration + name + Release + + 088AA6578212BE9BFBB07B70 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods.release.xcconfig + path + Pods/Target Support Files/Pods/Pods.release.xcconfig + sourceTree + <group> + + 1A943BF0259746F18D6E423F + + children + + 3D24B17D1E4A4E7A9566C5E9 + + isa + PBXGroup + name + Frameworks + sourceTree + <group> + + 1AE410B73DA5C3BD087ACDD7 + + children + + C068F1D3F0CC317E895FCDAB + 088AA6578212BE9BFBB07B70 + + isa + PBXGroup + name + Pods + sourceTree + <group> + + 3D24B17D1E4A4E7A9566C5E9 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods.a + sourceTree + BUILT_PRODUCTS_DIR + + 3EC0CDCBA10D483D9F386E5E + + fileRef + 3D24B17D1E4A4E7A9566C5E9 + isa + PBXBuildFile + + 6C2C82AA19EE274300767484 + + isa + PBXFileReference + lastKnownFileType + image.png + path + Default-667h@2x.png + sourceTree + SOURCE_ROOT + + 6C2C82AB19EE274300767484 + + isa + PBXFileReference + lastKnownFileType + image.png + path + Default-736h@3x.png + sourceTree + SOURCE_ROOT + + 6C2C82AC19EE274300767484 + + fileRef + 6C2C82AA19EE274300767484 + isa + PBXBuildFile + + 6C2C82AD19EE274300767484 + + fileRef + 6C2C82AB19EE274300767484 + isa + PBXBuildFile + + 6FBCCC34F8CCA9B610492536 + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Embed Pods Frameworks + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + "${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh" + + showEnvVarsInLog + 0 + + C068F1D3F0CC317E895FCDAB + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods.debug.xcconfig + path + Pods/Target Support Files/Pods/Pods.debug.xcconfig + sourceTree + <group> + + E080B80F89C34A25B3488E26 + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Check Pods Manifest.lock + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null +if [[ $? != 0 ]] ; then + cat << EOM +error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. +EOM + exit 1 +fi + + showEnvVarsInLog + 0 + + F012A6F39E0149F18F564F50 + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Copy Pods Resources + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + "${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh" + + showEnvVarsInLog + 0 + + + rootObject + 05E2127919D4DB510098F589 + + diff --git a/examples/EditableText/Sample.xcworkspace/contents.xcworkspacedata b/examples/EditableText/Sample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..7b5a2f3050 --- /dev/null +++ b/examples/EditableText/Sample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/examples/EditableText/Sample/ViewController.m b/examples/EditableText/Sample/ViewController.m index 6fb7070861..539f045480 100644 --- a/examples/EditableText/Sample/ViewController.m +++ b/examples/EditableText/Sample/ViewController.m @@ -17,6 +17,10 @@ @interface ViewController () { ASEditableTextNode *_textNode; + + // These elements are a test case for ASTextNode truncation. + UILabel *_label; + ASTextNode *_node; } @end @@ -44,6 +48,24 @@ // the usual delegate methods are available; see ASEditableTextNodeDelegate _textNode.delegate = self; + + + // Do any additional setup after loading the view, typically from a nib. + NSDictionary *attrs = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:12.0f] }; + NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"1\n2\n3\n4\n5" attributes:attrs]; + + _label = [[UILabel alloc] init]; + _label.attributedText = string; + _label.backgroundColor = [UIColor lightGrayColor]; + _label.numberOfLines = 3; + _label.frame = CGRectMake(20, 400, 40, 100); + + _node = [[ASTextNode alloc] init]; + _node.maximumNumberOfLines = 3; + _node.backgroundColor = [UIColor lightGrayColor]; + _node.attributedString = string; + _node.frame = CGRectMake(70, 400, 40, 100); +// [_node measure:CGSizeMake(40, 50)]; No longer needed now that https://github.com/facebook/AsyncDisplayKit/issues/1295 is fixed. return self; } @@ -53,6 +75,8 @@ [super viewDidLoad]; [self.view addSubnode:_textNode]; + [self.view addSubnode:_node]; + [self.view addSubview:_label]; [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]]; } diff --git a/examples/README.md b/examples/README.md index 358c9162ff..87c32c6375 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,6 +5,178 @@ Run `pod install` in each sample project directory to set up their dependencies. +## Example Catalog + +### ASCollectionView [ObjC] + +![ASCollectionView Example App Screenshot](./Screenshots/ASCollectionView.png?raw=true) + +Featuring: +- ASCollectionView with header/footer supplementary node support +- ASCollectionView batch API +- ASDelegateProxy + +### ASTableViewStressTest [ObjC] + +![ASTableViewStressTest Example App Screenshot](./Screenshots/ASTableViewStressTest.png?raw=true) + +### ASViewController [ObjC] + +![ASViewController Example App Screenshot](./Screenshots/ASViewController.png?raw=true) + +Featuring: +- ASViewController +- ASTableView +- ASMultiplexImageNode +- ASLayoutSpec + +### BackgroundPropertySetting [Swift] + +![BackgroundPropertySetting Example App gif](./Screenshots/BackgroundPropertySetting.gif?raw=true) + +Featuring: +- ASDK Swift compatibility +- ASViewController +- ASCollectionView +- thread affinity +- ASLayoutSpec + +### CarthageBuildTest +### CatDealsCollectionView [ObjC] + +![CatDealsCollectionView Example App Screenshot](./Screenshots/CatDealsCollectionView.png?raw=true) + +Featuring: +- ASCollectionView +- ASRangeTuningParameters +- Placeholder Images +- ASLayoutSpec + +### CollectionViewWithViewControllerCells [ObjC] + +![CollectionViewWithViewControllerCells Example App Screenshot](./Screenshots/CollectionViewWithViewControllerCells.png?raw=true) + +Featuring: +- custom collection view layout +- ASLayoutSpec +- ASMultiplexImageNode + +### CustomCollectionView [ObjC] + +![CustomCollectionView Example App gif](./Screenshots/CustomCollectionView.gif?raw=true) + +Featuring: +- custom collection view layout +- ASCollectionView with sections + +### EditableText [ObjC] + +![EditableText Example App Screenshot](./Screenshots/EditableText.png?raw=true) + +Featuring: +- ASEditableTextNode + +### HorizontalwithinVerticalScrolling [ObjC] + +![HorizontalwithinVerticalScrolling Example App gif](./Screenshots/HorizontalwithinVerticalScrolling.gif?raw=true) + +Featuring: +- UIViewController with ASTableView +- ASCollectionView +- ASCellNode + +### Kittens [ObjC] + +![Kittens Example App Screenshot](./Screenshots/Kittens.png?raw=true) + +Featuring: +- UIViewController with ASTableView +- ASCellNodes with ASNetworkImageNode and ASTextNode + +### Multiplex [ObjC] + +![Multiplex Example App gif](./Screenshots/Multiplex.gif?raw=true) + +Featuring: +- ASMultiplexImageNode (with artificial delay inserted) +- ASLayoutSpec + +### PagerNode [ObjC] + +Featuring: +- ASPagerNode + +### Placeholders [ObjC] + +Featuring: +- ASDisplayNodes now have an overidable method -placeholderImage that lets you provide a custom UIImage to display while a node is displaying asyncronously. The default implementation of this method returns nil and thus does nothing. A provided example project also demonstrates using the placeholder API. + +### SocialAppLayout [ObjC] + +![SocialAppLayout Example App Screenshot](./Screenshots/SocialAppLayout.png?raw=true) + +Featuring: +- ASLayoutSpec +- UIViewController with ASTableView + +### Swift [Swift] + +![Swift Example App Screenshot](./Screenshots/Swift.png?raw=true) + +Featuring: +- ASViewController with ASTableNode + +### SynchronousConcurrency [ObjC] + +![SynchronousConcurrency Example App Screenshot](./Screenshots/SynchronousConcurrency.png?raw=true) + +Implementation of Synchronous Concurrency features for AsyncDisplayKit 2.0 + +This provides internal features on _ASAsyncTransaction and ASDisplayNode to facilitate +implementing public API that allows clients to choose if they would prefer to block +on the completion of unfinished rendering, rather than allow a placeholder state to +become visible. + +The internal features are: +-[_ASAsyncTransaction waitUntilComplete] +-[ASDisplayNode recursivelyEnsureDisplay] + +Also provided are two such implementations: +-[ASCellNode setNeverShowPlaceholders:], which integrates with both Tables and Collections +-[ASViewController setNeverShowPlaceholders:], which should work with Nav and Tab controllers. + +Lastly, on ASDisplayNode, a new property .shouldBypassEnsureDisplay allows individual node types +to exempt themselves from blocking the main thread on their display. + +By implementing the feature at the ASCellNode level rather than ASTableView & ASCollectionView, +developers can retain fine-grained control on display characteristics. For example, certain +cell types may be appropriate to display to the user with placeholders, whereas others may not. + +### SynchronousKittens [ObjC] + +### VerticalWithinHorizontalScrolling [ObjC] + +![VerticalWithinHorizontalScrolling Example App Screenshot](./Screenshots/VerticalWithinHorizontalScrolling.png?raw=true) + +Features: +- UIViewController containing ASPagerNode containing ASTableNodes + +### Videos [ObjC] + +![VideoTableView Example App gif](./Screenshots/Videos.gif?raw=true) + +Featuring: +- ASVideoNode + +### VideoTableView [ObjC] + +![VideoTableView Example App Screenshot](./Screenshots/VideoTableView.png?raw=true) + +Featuring: +- ASVideoNode +- ASTableView +- ASCellNode + ## License This file provided by Facebook is for non-commercial testing and evaluation diff --git a/examples/Screenshots/ASCollectionView.png b/examples/Screenshots/ASCollectionView.png new file mode 100644 index 0000000000..3aaff368e5 Binary files /dev/null and b/examples/Screenshots/ASCollectionView.png differ diff --git a/examples/Screenshots/ASTableViewStressTest.png b/examples/Screenshots/ASTableViewStressTest.png new file mode 100644 index 0000000000..cd7aae2d9d Binary files /dev/null and b/examples/Screenshots/ASTableViewStressTest.png differ diff --git a/examples/Screenshots/ASViewController.png b/examples/Screenshots/ASViewController.png new file mode 100644 index 0000000000..545f3c8d63 Binary files /dev/null and b/examples/Screenshots/ASViewController.png differ diff --git a/examples/Screenshots/BackgroundPropertySetting.gif b/examples/Screenshots/BackgroundPropertySetting.gif new file mode 100644 index 0000000000..e2655ef235 Binary files /dev/null and b/examples/Screenshots/BackgroundPropertySetting.gif differ diff --git a/examples/Screenshots/CatDealsCollectionView.png b/examples/Screenshots/CatDealsCollectionView.png new file mode 100644 index 0000000000..72f9179e94 Binary files /dev/null and b/examples/Screenshots/CatDealsCollectionView.png differ diff --git a/examples/Screenshots/CollectionViewWithViewControllerCells.png b/examples/Screenshots/CollectionViewWithViewControllerCells.png new file mode 100644 index 0000000000..078b7b945f Binary files /dev/null and b/examples/Screenshots/CollectionViewWithViewControllerCells.png differ diff --git a/examples/Screenshots/CustomCollectionView.gif b/examples/Screenshots/CustomCollectionView.gif new file mode 100644 index 0000000000..8d8a2aed1e Binary files /dev/null and b/examples/Screenshots/CustomCollectionView.gif differ diff --git a/examples/Screenshots/EditableText.png b/examples/Screenshots/EditableText.png new file mode 100644 index 0000000000..1aa8d6db9b Binary files /dev/null and b/examples/Screenshots/EditableText.png differ diff --git a/examples/Screenshots/HorizontalwithinVerticalScrolling.gif b/examples/Screenshots/HorizontalwithinVerticalScrolling.gif new file mode 100644 index 0000000000..fe722a308d Binary files /dev/null and b/examples/Screenshots/HorizontalwithinVerticalScrolling.gif differ diff --git a/examples/Screenshots/Kittens.png b/examples/Screenshots/Kittens.png new file mode 100644 index 0000000000..91d9bf36fa Binary files /dev/null and b/examples/Screenshots/Kittens.png differ diff --git a/examples/Screenshots/Multiplex.gif b/examples/Screenshots/Multiplex.gif new file mode 100644 index 0000000000..fcb98cad62 Binary files /dev/null and b/examples/Screenshots/Multiplex.gif differ diff --git a/examples/Screenshots/SocialAppLayout.png b/examples/Screenshots/SocialAppLayout.png new file mode 100644 index 0000000000..33d6672102 Binary files /dev/null and b/examples/Screenshots/SocialAppLayout.png differ diff --git a/examples/Screenshots/Swift.png b/examples/Screenshots/Swift.png new file mode 100644 index 0000000000..b099a17229 Binary files /dev/null and b/examples/Screenshots/Swift.png differ diff --git a/examples/Screenshots/SynchronousConcurrency.png b/examples/Screenshots/SynchronousConcurrency.png new file mode 100644 index 0000000000..e0eac3788e Binary files /dev/null and b/examples/Screenshots/SynchronousConcurrency.png differ diff --git a/examples/Screenshots/VerticalWithinHorizontalScrolling.gif b/examples/Screenshots/VerticalWithinHorizontalScrolling.gif new file mode 100644 index 0000000000..c50474b19b Binary files /dev/null and b/examples/Screenshots/VerticalWithinHorizontalScrolling.gif differ diff --git a/examples/Screenshots/VideoTableView.png b/examples/Screenshots/VideoTableView.png new file mode 100644 index 0000000000..ddeefdc773 Binary files /dev/null and b/examples/Screenshots/VideoTableView.png differ diff --git a/examples/Screenshots/Videos.gif b/examples/Screenshots/Videos.gif new file mode 100644 index 0000000000..5e5c5f2ca9 Binary files /dev/null and b/examples/Screenshots/Videos.gif differ diff --git a/examples/SocialAppLayout/Sample.xcodeproj/project.pbxproj b/examples/SocialAppLayout/Sample.xcodeproj/project.pbxproj index 6b5d2a4bbf..b14014b7a0 100644 --- a/examples/SocialAppLayout/Sample.xcodeproj/project.pbxproj +++ b/examples/SocialAppLayout/Sample.xcodeproj/project.pbxproj @@ -1,466 +1,1311 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1DAE4C3A5DA2C2B081CD640F /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7577801AA7321797C5FBB9A1 /* libPods.a */; }; - 3EEA4EE91BECC4A1008A7F35 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4EE81BECC4A1008A7F35 /* main.m */; }; - 3EEA4EEC1BECC4A1008A7F35 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4EEB1BECC4A1008A7F35 /* AppDelegate.m */; }; - 3EEA4EEF1BECC4A1008A7F35 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4EEE1BECC4A1008A7F35 /* ViewController.m */; }; - 3EEA4EF41BECC4A1008A7F35 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4EF31BECC4A1008A7F35 /* Assets.xcassets */; }; - 3EEA4F011BECC4E8008A7F35 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4EFE1BECC4E8008A7F35 /* Default-568h@2x.png */; }; - 3EEA4F021BECC4E8008A7F35 /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4EFF1BECC4E8008A7F35 /* Default-667h@2x.png */; }; - 3EEA4F031BECC4E8008A7F35 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F001BECC4E8008A7F35 /* Default-736h@3x.png */; }; - 3EEA4F061BECC6C9008A7F35 /* Post.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4F051BECC6C9008A7F35 /* Post.m */; }; - 3EEA4F091BECC855008A7F35 /* PostNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4F081BECC855008A7F35 /* PostNode.m */; }; - 3EEA4F0C1BECCA0A008A7F35 /* TextStyles.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4F0B1BECCA0A008A7F35 /* TextStyles.m */; }; - 3EEA4F141BECDCD6008A7F35 /* icon_android.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F0E1BECDCD6008A7F35 /* icon_android.png */; }; - 3EEA4F151BECDCD6008A7F35 /* icon_android@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F0F1BECDCD6008A7F35 /* icon_android@2x.png */; }; - 3EEA4F161BECDCD6008A7F35 /* icon_android@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F101BECDCD6008A7F35 /* icon_android@3x.png */; }; - 3EEA4F171BECDCD6008A7F35 /* icon_ios.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F111BECDCD6008A7F35 /* icon_ios.png */; }; - 3EEA4F181BECDCD6008A7F35 /* icon_ios@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F121BECDCD6008A7F35 /* icon_ios@2x.png */; }; - 3EEA4F191BECDCD6008A7F35 /* icon_ios@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F131BECDCD6008A7F35 /* icon_ios@3x.png */; }; - 3EEA4F1D1BECE358008A7F35 /* LikesNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4F1C1BECE358008A7F35 /* LikesNode.m */; }; - 3EEA4F2A1BECE440008A7F35 /* icon_liked.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F1E1BECE440008A7F35 /* icon_liked.png */; }; - 3EEA4F2B1BECE440008A7F35 /* icon_liked@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F1F1BECE440008A7F35 /* icon_liked@2x.png */; }; - 3EEA4F2C1BECE440008A7F35 /* icon_liked@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F201BECE440008A7F35 /* icon_liked@3x.png */; }; - 3EEA4F301BECE440008A7F35 /* icon_like@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F241BECE440008A7F35 /* icon_like@3x.png */; }; - 3EEA4F311BECE440008A7F35 /* icon_like@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F251BECE440008A7F35 /* icon_like@2x.png */; }; - 3EEA4F321BECE440008A7F35 /* icon_like.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F261BECE440008A7F35 /* icon_like.png */; }; - 3EEA4F331BECE440008A7F35 /* icon_comment@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F271BECE440008A7F35 /* icon_comment@3x.png */; }; - 3EEA4F341BECE440008A7F35 /* icon_comment@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F281BECE440008A7F35 /* icon_comment@2x.png */; }; - 3EEA4F351BECE440008A7F35 /* icon_comment.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F291BECE440008A7F35 /* icon_comment.png */; }; - 3EEA4F381BECE775008A7F35 /* CommentsNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEA4F371BECE775008A7F35 /* CommentsNode.m */; }; - 3EEA4F3C1BECE99F008A7F35 /* icon_more.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F391BECE99F008A7F35 /* icon_more.png */; }; - 3EEA4F3D1BECE99F008A7F35 /* icon_more@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F3A1BECE99F008A7F35 /* icon_more@2x.png */; }; - 3EEA4F3E1BECE99F008A7F35 /* icon_more@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3EEA4F3B1BECE99F008A7F35 /* icon_more@3x.png */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 3EEA4EE41BECC4A1008A7F35 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 3EEA4EE81BECC4A1008A7F35 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 3EEA4EEA1BECC4A1008A7F35 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 3EEA4EEB1BECC4A1008A7F35 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 3EEA4EED1BECC4A1008A7F35 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - 3EEA4EEE1BECC4A1008A7F35 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - 3EEA4EF31BECC4A1008A7F35 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 3EEA4EF81BECC4A1008A7F35 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 3EEA4EFE1BECC4E8008A7F35 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; - 3EEA4EFF1BECC4E8008A7F35 /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = ""; }; - 3EEA4F001BECC4E8008A7F35 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = ""; }; - 3EEA4F041BECC6C9008A7F35 /* Post.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Post.h; sourceTree = ""; }; - 3EEA4F051BECC6C9008A7F35 /* Post.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Post.m; sourceTree = ""; }; - 3EEA4F071BECC855008A7F35 /* PostNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PostNode.h; sourceTree = ""; }; - 3EEA4F081BECC855008A7F35 /* PostNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PostNode.m; sourceTree = ""; }; - 3EEA4F0A1BECCA0A008A7F35 /* TextStyles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextStyles.h; sourceTree = ""; }; - 3EEA4F0B1BECCA0A008A7F35 /* TextStyles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextStyles.m; sourceTree = ""; }; - 3EEA4F0E1BECDCD6008A7F35 /* icon_android.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_android.png; sourceTree = ""; }; - 3EEA4F0F1BECDCD6008A7F35 /* icon_android@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_android@2x.png"; sourceTree = ""; }; - 3EEA4F101BECDCD6008A7F35 /* icon_android@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_android@3x.png"; sourceTree = ""; }; - 3EEA4F111BECDCD6008A7F35 /* icon_ios.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_ios.png; sourceTree = ""; }; - 3EEA4F121BECDCD6008A7F35 /* icon_ios@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_ios@2x.png"; sourceTree = ""; }; - 3EEA4F131BECDCD6008A7F35 /* icon_ios@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_ios@3x.png"; sourceTree = ""; }; - 3EEA4F1B1BECE358008A7F35 /* LikesNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LikesNode.h; sourceTree = ""; }; - 3EEA4F1C1BECE358008A7F35 /* LikesNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LikesNode.m; sourceTree = ""; }; - 3EEA4F1E1BECE440008A7F35 /* icon_liked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_liked.png; sourceTree = ""; }; - 3EEA4F1F1BECE440008A7F35 /* icon_liked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_liked@2x.png"; sourceTree = ""; }; - 3EEA4F201BECE440008A7F35 /* icon_liked@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_liked@3x.png"; sourceTree = ""; }; - 3EEA4F241BECE440008A7F35 /* icon_like@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_like@3x.png"; sourceTree = ""; }; - 3EEA4F251BECE440008A7F35 /* icon_like@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_like@2x.png"; sourceTree = ""; }; - 3EEA4F261BECE440008A7F35 /* icon_like.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_like.png; sourceTree = ""; }; - 3EEA4F271BECE440008A7F35 /* icon_comment@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_comment@3x.png"; sourceTree = ""; }; - 3EEA4F281BECE440008A7F35 /* icon_comment@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_comment@2x.png"; sourceTree = ""; }; - 3EEA4F291BECE440008A7F35 /* icon_comment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_comment.png; sourceTree = ""; }; - 3EEA4F361BECE775008A7F35 /* CommentsNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommentsNode.h; sourceTree = ""; }; - 3EEA4F371BECE775008A7F35 /* CommentsNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommentsNode.m; sourceTree = ""; }; - 3EEA4F391BECE99F008A7F35 /* icon_more.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_more.png; sourceTree = ""; }; - 3EEA4F3A1BECE99F008A7F35 /* icon_more@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_more@2x.png"; sourceTree = ""; }; - 3EEA4F3B1BECE99F008A7F35 /* icon_more@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_more@3x.png"; sourceTree = ""; }; - 7577801AA7321797C5FBB9A1 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 839964CA580D0ED921A6FCB1 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; - E38AD915EE10CFC641F39E5C /* 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 */ - 3EEA4EE11BECC4A1008A7F35 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1DAE4C3A5DA2C2B081CD640F /* libPods.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 3EEA4EDB1BECC4A1008A7F35 = { - isa = PBXGroup; - children = ( - 3EEA4EE61BECC4A1008A7F35 /* Sample */, - 3EEA4EE51BECC4A1008A7F35 /* Products */, - 842ADAFE88475D19B24183AC /* Pods */, - EED34FA6D8171DF44757C852 /* Frameworks */, - ); - sourceTree = ""; - }; - 3EEA4EE51BECC4A1008A7F35 /* Products */ = { - isa = PBXGroup; - children = ( - 3EEA4EE41BECC4A1008A7F35 /* Sample.app */, - ); - name = Products; - sourceTree = ""; - }; - 3EEA4EE61BECC4A1008A7F35 /* Sample */ = { - isa = PBXGroup; - children = ( - 3EEA4F0D1BECDCA6008A7F35 /* Images */, - 3EEA4EEA1BECC4A1008A7F35 /* AppDelegate.h */, - 3EEA4EEB1BECC4A1008A7F35 /* AppDelegate.m */, - 3EEA4EED1BECC4A1008A7F35 /* ViewController.h */, - 3EEA4EEE1BECC4A1008A7F35 /* ViewController.m */, - 3EEA4EF31BECC4A1008A7F35 /* Assets.xcassets */, - 3EEA4EF81BECC4A1008A7F35 /* Info.plist */, - 3EEA4EE71BECC4A1008A7F35 /* Supporting Files */, - 3EEA4F041BECC6C9008A7F35 /* Post.h */, - 3EEA4F051BECC6C9008A7F35 /* Post.m */, - 3EEA4F071BECC855008A7F35 /* PostNode.h */, - 3EEA4F081BECC855008A7F35 /* PostNode.m */, - 3EEA4F0A1BECCA0A008A7F35 /* TextStyles.h */, - 3EEA4F0B1BECCA0A008A7F35 /* TextStyles.m */, - 3EEA4F1B1BECE358008A7F35 /* LikesNode.h */, - 3EEA4F1C1BECE358008A7F35 /* LikesNode.m */, - 3EEA4F361BECE775008A7F35 /* CommentsNode.h */, - 3EEA4F371BECE775008A7F35 /* CommentsNode.m */, - ); - path = Sample; - sourceTree = ""; - }; - 3EEA4EE71BECC4A1008A7F35 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 3EEA4EFE1BECC4E8008A7F35 /* Default-568h@2x.png */, - 3EEA4EFF1BECC4E8008A7F35 /* Default-667h@2x.png */, - 3EEA4F001BECC4E8008A7F35 /* Default-736h@3x.png */, - 3EEA4EE81BECC4A1008A7F35 /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 3EEA4F0D1BECDCA6008A7F35 /* Images */ = { - isa = PBXGroup; - children = ( - 3EEA4F391BECE99F008A7F35 /* icon_more.png */, - 3EEA4F3A1BECE99F008A7F35 /* icon_more@2x.png */, - 3EEA4F3B1BECE99F008A7F35 /* icon_more@3x.png */, - 3EEA4F1E1BECE440008A7F35 /* icon_liked.png */, - 3EEA4F1F1BECE440008A7F35 /* icon_liked@2x.png */, - 3EEA4F201BECE440008A7F35 /* icon_liked@3x.png */, - 3EEA4F241BECE440008A7F35 /* icon_like@3x.png */, - 3EEA4F251BECE440008A7F35 /* icon_like@2x.png */, - 3EEA4F261BECE440008A7F35 /* icon_like.png */, - 3EEA4F271BECE440008A7F35 /* icon_comment@3x.png */, - 3EEA4F281BECE440008A7F35 /* icon_comment@2x.png */, - 3EEA4F291BECE440008A7F35 /* icon_comment.png */, - 3EEA4F0E1BECDCD6008A7F35 /* icon_android.png */, - 3EEA4F0F1BECDCD6008A7F35 /* icon_android@2x.png */, - 3EEA4F101BECDCD6008A7F35 /* icon_android@3x.png */, - 3EEA4F111BECDCD6008A7F35 /* icon_ios.png */, - 3EEA4F121BECDCD6008A7F35 /* icon_ios@2x.png */, - 3EEA4F131BECDCD6008A7F35 /* icon_ios@3x.png */, - ); - name = Images; - sourceTree = ""; - }; - 842ADAFE88475D19B24183AC /* Pods */ = { - isa = PBXGroup; - children = ( - E38AD915EE10CFC641F39E5C /* Pods.debug.xcconfig */, - 839964CA580D0ED921A6FCB1 /* Pods.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - EED34FA6D8171DF44757C852 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 7577801AA7321797C5FBB9A1 /* libPods.a */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 3EEA4EE31BECC4A1008A7F35 /* Sample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3EEA4EFB1BECC4A1008A7F35 /* Build configuration list for PBXNativeTarget "Sample" */; - buildPhases = ( - B5BD9E5609B2CB179EEE0CF4 /* Check Pods Manifest.lock */, - 3EEA4EE01BECC4A1008A7F35 /* Sources */, - 3EEA4EE11BECC4A1008A7F35 /* Frameworks */, - 3EEA4EE21BECC4A1008A7F35 /* Resources */, - 21F2C1D9B53F9468EAF1653F /* Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Sample; - productName = Sample; - productReference = 3EEA4EE41BECC4A1008A7F35 /* Sample.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 3EEA4EDC1BECC4A1008A7F35 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0710; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 3EEA4EE31BECC4A1008A7F35 = { - CreatedOnToolsVersion = 7.1; - }; - }; - }; - buildConfigurationList = 3EEA4EDF1BECC4A1008A7F35 /* Build configuration list for PBXProject "Sample" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 3EEA4EDB1BECC4A1008A7F35; - productRefGroup = 3EEA4EE51BECC4A1008A7F35 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 3EEA4EE31BECC4A1008A7F35 /* Sample */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 3EEA4EE21BECC4A1008A7F35 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3EEA4F2A1BECE440008A7F35 /* icon_liked.png in Resources */, - 3EEA4F181BECDCD6008A7F35 /* icon_ios@2x.png in Resources */, - 3EEA4F311BECE440008A7F35 /* icon_like@2x.png in Resources */, - 3EEA4F3D1BECE99F008A7F35 /* icon_more@2x.png in Resources */, - 3EEA4F141BECDCD6008A7F35 /* icon_android.png in Resources */, - 3EEA4F3E1BECE99F008A7F35 /* icon_more@3x.png in Resources */, - 3EEA4F2B1BECE440008A7F35 /* icon_liked@2x.png in Resources */, - 3EEA4F351BECE440008A7F35 /* icon_comment.png in Resources */, - 3EEA4EF41BECC4A1008A7F35 /* Assets.xcassets in Resources */, - 3EEA4F171BECDCD6008A7F35 /* icon_ios.png in Resources */, - 3EEA4F021BECC4E8008A7F35 /* Default-667h@2x.png in Resources */, - 3EEA4F161BECDCD6008A7F35 /* icon_android@3x.png in Resources */, - 3EEA4F191BECDCD6008A7F35 /* icon_ios@3x.png in Resources */, - 3EEA4F331BECE440008A7F35 /* icon_comment@3x.png in Resources */, - 3EEA4F341BECE440008A7F35 /* icon_comment@2x.png in Resources */, - 3EEA4F321BECE440008A7F35 /* icon_like.png in Resources */, - 3EEA4F151BECDCD6008A7F35 /* icon_android@2x.png in Resources */, - 3EEA4F301BECE440008A7F35 /* icon_like@3x.png in Resources */, - 3EEA4F2C1BECE440008A7F35 /* icon_liked@3x.png in Resources */, - 3EEA4F011BECC4E8008A7F35 /* Default-568h@2x.png in Resources */, - 3EEA4F031BECC4E8008A7F35 /* Default-736h@3x.png in Resources */, - 3EEA4F3C1BECE99F008A7F35 /* icon_more.png in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 21F2C1D9B53F9468EAF1653F /* 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; - }; - B5BD9E5609B2CB179EEE0CF4 /* 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 */ - 3EEA4EE01BECC4A1008A7F35 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3EEA4EEF1BECC4A1008A7F35 /* ViewController.m in Sources */, - 3EEA4EEC1BECC4A1008A7F35 /* AppDelegate.m in Sources */, - 3EEA4EE91BECC4A1008A7F35 /* main.m in Sources */, - 3EEA4F061BECC6C9008A7F35 /* Post.m in Sources */, - 3EEA4F0C1BECCA0A008A7F35 /* TextStyles.m in Sources */, - 3EEA4F381BECE775008A7F35 /* CommentsNode.m in Sources */, - 3EEA4F091BECC855008A7F35 /* PostNode.m in Sources */, - 3EEA4F1D1BECE358008A7F35 /* LikesNode.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 3EEA4EF91BECC4A1008A7F35 /* 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.1; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 3EEA4EFA1BECC4A1008A7F35 /* 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.1; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 3EEA4EFC1BECC4A1008A7F35 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E38AD915EE10CFC641F39E5C /* Pods.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Sample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.facebook.AsyncDisplayKit.Sample; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 3EEA4EFD1BECC4A1008A7F35 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 839964CA580D0ED921A6FCB1 /* Pods.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Sample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.facebook.AsyncDisplayKit.Sample; - PRODUCT_NAME = "$(TARGET_NAME)"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 3EEA4EDF1BECC4A1008A7F35 /* Build configuration list for PBXProject "Sample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3EEA4EF91BECC4A1008A7F35 /* Debug */, - 3EEA4EFA1BECC4A1008A7F35 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3EEA4EFB1BECC4A1008A7F35 /* Build configuration list for PBXNativeTarget "Sample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3EEA4EFC1BECC4A1008A7F35 /* Debug */, - 3EEA4EFD1BECC4A1008A7F35 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 3EEA4EDC1BECC4A1008A7F35 /* Project object */; -} + + + + + archiveVersion + 1 + classes + + objectVersion + 46 + objects + + 1DAE4C3A5DA2C2B081CD640F + + fileRef + 7577801AA7321797C5FBB9A1 + isa + PBXBuildFile + + 21F2C1D9B53F9468EAF1653F + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Copy Pods Resources + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + "${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh" + + showEnvVarsInLog + 0 + + 3EEA4EDB1BECC4A1008A7F35 + + children + + 3EEA4EE61BECC4A1008A7F35 + 3EEA4EE51BECC4A1008A7F35 + 842ADAFE88475D19B24183AC + EED34FA6D8171DF44757C852 + + isa + PBXGroup + sourceTree + <group> + + 3EEA4EDC1BECC4A1008A7F35 + + attributes + + LastUpgradeCheck + 0710 + ORGANIZATIONNAME + Facebook + TargetAttributes + + 3EEA4EE31BECC4A1008A7F35 + + CreatedOnToolsVersion + 7.1 + + + + buildConfigurationList + 3EEA4EDF1BECC4A1008A7F35 + compatibilityVersion + Xcode 3.2 + developmentRegion + English + hasScannedForEncodings + 0 + isa + PBXProject + knownRegions + + en + Base + + mainGroup + 3EEA4EDB1BECC4A1008A7F35 + productRefGroup + 3EEA4EE51BECC4A1008A7F35 + projectDirPath + + projectReferences + + projectRoot + + targets + + 3EEA4EE31BECC4A1008A7F35 + + + 3EEA4EDF1BECC4A1008A7F35 + + buildConfigurations + + 3EEA4EF91BECC4A1008A7F35 + 3EEA4EFA1BECC4A1008A7F35 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 3EEA4EE01BECC4A1008A7F35 + + buildActionMask + 2147483647 + files + + 3EEA4EEF1BECC4A1008A7F35 + 3EEA4EEC1BECC4A1008A7F35 + 3EEA4EE91BECC4A1008A7F35 + 3EEA4F061BECC6C9008A7F35 + 3EEA4F0C1BECCA0A008A7F35 + 3EEA4F381BECE775008A7F35 + 3EEA4F091BECC855008A7F35 + 3EEA4F1D1BECE358008A7F35 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3EEA4EE11BECC4A1008A7F35 + + buildActionMask + 2147483647 + files + + 1DAE4C3A5DA2C2B081CD640F + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3EEA4EE21BECC4A1008A7F35 + + buildActionMask + 2147483647 + files + + 3EEA4F2A1BECE440008A7F35 + 3EEA4F181BECDCD6008A7F35 + 3EEA4F311BECE440008A7F35 + 3EEA4F3D1BECE99F008A7F35 + 3EEA4F141BECDCD6008A7F35 + 3EEA4F3E1BECE99F008A7F35 + 3EEA4F2B1BECE440008A7F35 + 3EEA4F351BECE440008A7F35 + 3EEA4EF41BECC4A1008A7F35 + 3EEA4F171BECDCD6008A7F35 + 3EEA4F021BECC4E8008A7F35 + 3EEA4F161BECDCD6008A7F35 + 3EEA4F191BECDCD6008A7F35 + 3EEA4F331BECE440008A7F35 + 3EEA4F341BECE440008A7F35 + 3EEA4F321BECE440008A7F35 + 3EEA4F151BECDCD6008A7F35 + 3EEA4F301BECE440008A7F35 + 3EEA4F2C1BECE440008A7F35 + 3EEA4F011BECC4E8008A7F35 + 3EEA4F031BECC4E8008A7F35 + 3EEA4F3C1BECE99F008A7F35 + + isa + PBXResourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3EEA4EE31BECC4A1008A7F35 + + buildConfigurationList + 3EEA4EFB1BECC4A1008A7F35 + buildPhases + + B5BD9E5609B2CB179EEE0CF4 + 3EEA4EE01BECC4A1008A7F35 + 3EEA4EE11BECC4A1008A7F35 + 3EEA4EE21BECC4A1008A7F35 + 21F2C1D9B53F9468EAF1653F + 852437589F1D53B9483A75DF + + buildRules + + dependencies + + isa + PBXNativeTarget + name + Sample + productName + Sample + productReference + 3EEA4EE41BECC4A1008A7F35 + productType + com.apple.product-type.application + + 3EEA4EE41BECC4A1008A7F35 + + explicitFileType + wrapper.application + includeInIndex + 0 + isa + PBXFileReference + path + Sample.app + sourceTree + BUILT_PRODUCTS_DIR + + 3EEA4EE51BECC4A1008A7F35 + + children + + 3EEA4EE41BECC4A1008A7F35 + + isa + PBXGroup + name + Products + sourceTree + <group> + + 3EEA4EE61BECC4A1008A7F35 + + children + + 3EEA4F0D1BECDCA6008A7F35 + 3EEA4EEA1BECC4A1008A7F35 + 3EEA4EEB1BECC4A1008A7F35 + 3EEA4EED1BECC4A1008A7F35 + 3EEA4EEE1BECC4A1008A7F35 + 3EEA4EF31BECC4A1008A7F35 + 3EEA4EF81BECC4A1008A7F35 + 3EEA4EE71BECC4A1008A7F35 + 3EEA4F041BECC6C9008A7F35 + 3EEA4F051BECC6C9008A7F35 + 3EEA4F071BECC855008A7F35 + 3EEA4F081BECC855008A7F35 + 3EEA4F0A1BECCA0A008A7F35 + 3EEA4F0B1BECCA0A008A7F35 + 3EEA4F1B1BECE358008A7F35 + 3EEA4F1C1BECE358008A7F35 + 3EEA4F361BECE775008A7F35 + 3EEA4F371BECE775008A7F35 + + isa + PBXGroup + path + Sample + sourceTree + <group> + + 3EEA4EE71BECC4A1008A7F35 + + children + + 3EEA4EFE1BECC4E8008A7F35 + 3EEA4EFF1BECC4E8008A7F35 + 3EEA4F001BECC4E8008A7F35 + 3EEA4EE81BECC4A1008A7F35 + + isa + PBXGroup + name + Supporting Files + sourceTree + <group> + + 3EEA4EE81BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + main.m + sourceTree + <group> + + 3EEA4EE91BECC4A1008A7F35 + + fileRef + 3EEA4EE81BECC4A1008A7F35 + isa + PBXBuildFile + + 3EEA4EEA1BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + AppDelegate.h + sourceTree + <group> + + 3EEA4EEB1BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + AppDelegate.m + sourceTree + <group> + + 3EEA4EEC1BECC4A1008A7F35 + + fileRef + 3EEA4EEB1BECC4A1008A7F35 + isa + PBXBuildFile + + 3EEA4EED1BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + ViewController.h + sourceTree + <group> + + 3EEA4EEE1BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + ViewController.m + sourceTree + <group> + + 3EEA4EEF1BECC4A1008A7F35 + + fileRef + 3EEA4EEE1BECC4A1008A7F35 + isa + PBXBuildFile + + 3EEA4EF31BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + folder.assetcatalog + path + Assets.xcassets + sourceTree + <group> + + 3EEA4EF41BECC4A1008A7F35 + + fileRef + 3EEA4EF31BECC4A1008A7F35 + isa + PBXBuildFile + + 3EEA4EF81BECC4A1008A7F35 + + isa + PBXFileReference + lastKnownFileType + text.plist.xml + path + Info.plist + sourceTree + <group> + + 3EEA4EF91BECC4A1008A7F35 + + 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.1 + MTL_ENABLE_DEBUG_INFO + YES + ONLY_ACTIVE_ARCH + YES + SDKROOT + iphoneos + + isa + XCBuildConfiguration + name + Debug + + 3EEA4EFA1BECC4A1008A7F35 + + 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.1 + MTL_ENABLE_DEBUG_INFO + NO + SDKROOT + iphoneos + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 3EEA4EFB1BECC4A1008A7F35 + + buildConfigurations + + 3EEA4EFC1BECC4A1008A7F35 + 3EEA4EFD1BECC4A1008A7F35 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 3EEA4EFC1BECC4A1008A7F35 + + baseConfigurationReference + E38AD915EE10CFC641F39E5C + buildSettings + + ASSETCATALOG_COMPILER_APPICON_NAME + AppIcon + INFOPLIST_FILE + Sample/Info.plist + IPHONEOS_DEPLOYMENT_TARGET + 7.1 + LD_RUNPATH_SEARCH_PATHS + $(inherited) @executable_path/Frameworks + PRODUCT_BUNDLE_IDENTIFIER + com.facebook.AsyncDisplayKit.Sample + PRODUCT_NAME + $(TARGET_NAME) + TARGETED_DEVICE_FAMILY + 1,2 + + isa + XCBuildConfiguration + name + Debug + + 3EEA4EFD1BECC4A1008A7F35 + + baseConfigurationReference + 839964CA580D0ED921A6FCB1 + buildSettings + + ASSETCATALOG_COMPILER_APPICON_NAME + AppIcon + INFOPLIST_FILE + Sample/Info.plist + IPHONEOS_DEPLOYMENT_TARGET + 7.1 + LD_RUNPATH_SEARCH_PATHS + $(inherited) @executable_path/Frameworks + PRODUCT_BUNDLE_IDENTIFIER + com.facebook.AsyncDisplayKit.Sample + PRODUCT_NAME + $(TARGET_NAME) + TARGETED_DEVICE_FAMILY + 1,2 + + isa + XCBuildConfiguration + name + Release + + 3EEA4EFE1BECC4E8008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + Default-568h@2x.png + sourceTree + <group> + + 3EEA4EFF1BECC4E8008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + Default-667h@2x.png + sourceTree + <group> + + 3EEA4F001BECC4E8008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + Default-736h@3x.png + sourceTree + <group> + + 3EEA4F011BECC4E8008A7F35 + + fileRef + 3EEA4EFE1BECC4E8008A7F35 + isa + PBXBuildFile + + 3EEA4F021BECC4E8008A7F35 + + fileRef + 3EEA4EFF1BECC4E8008A7F35 + isa + PBXBuildFile + + 3EEA4F031BECC4E8008A7F35 + + fileRef + 3EEA4F001BECC4E8008A7F35 + isa + PBXBuildFile + + 3EEA4F041BECC6C9008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + Post.h + sourceTree + <group> + + 3EEA4F051BECC6C9008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + Post.m + sourceTree + <group> + + 3EEA4F061BECC6C9008A7F35 + + fileRef + 3EEA4F051BECC6C9008A7F35 + isa + PBXBuildFile + + 3EEA4F071BECC855008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + PostNode.h + sourceTree + <group> + + 3EEA4F081BECC855008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + PostNode.m + sourceTree + <group> + + 3EEA4F091BECC855008A7F35 + + fileRef + 3EEA4F081BECC855008A7F35 + isa + PBXBuildFile + + 3EEA4F0A1BECCA0A008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + TextStyles.h + sourceTree + <group> + + 3EEA4F0B1BECCA0A008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + TextStyles.m + sourceTree + <group> + + 3EEA4F0C1BECCA0A008A7F35 + + fileRef + 3EEA4F0B1BECCA0A008A7F35 + isa + PBXBuildFile + + 3EEA4F0D1BECDCA6008A7F35 + + children + + 3EEA4F391BECE99F008A7F35 + 3EEA4F3A1BECE99F008A7F35 + 3EEA4F3B1BECE99F008A7F35 + 3EEA4F1E1BECE440008A7F35 + 3EEA4F1F1BECE440008A7F35 + 3EEA4F201BECE440008A7F35 + 3EEA4F241BECE440008A7F35 + 3EEA4F251BECE440008A7F35 + 3EEA4F261BECE440008A7F35 + 3EEA4F271BECE440008A7F35 + 3EEA4F281BECE440008A7F35 + 3EEA4F291BECE440008A7F35 + 3EEA4F0E1BECDCD6008A7F35 + 3EEA4F0F1BECDCD6008A7F35 + 3EEA4F101BECDCD6008A7F35 + 3EEA4F111BECDCD6008A7F35 + 3EEA4F121BECDCD6008A7F35 + 3EEA4F131BECDCD6008A7F35 + + isa + PBXGroup + name + Images + sourceTree + <group> + + 3EEA4F0E1BECDCD6008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_android.png + sourceTree + <group> + + 3EEA4F0F1BECDCD6008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_android@2x.png + sourceTree + <group> + + 3EEA4F101BECDCD6008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_android@3x.png + sourceTree + <group> + + 3EEA4F111BECDCD6008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_ios.png + sourceTree + <group> + + 3EEA4F121BECDCD6008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_ios@2x.png + sourceTree + <group> + + 3EEA4F131BECDCD6008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_ios@3x.png + sourceTree + <group> + + 3EEA4F141BECDCD6008A7F35 + + fileRef + 3EEA4F0E1BECDCD6008A7F35 + isa + PBXBuildFile + + 3EEA4F151BECDCD6008A7F35 + + fileRef + 3EEA4F0F1BECDCD6008A7F35 + isa + PBXBuildFile + + 3EEA4F161BECDCD6008A7F35 + + fileRef + 3EEA4F101BECDCD6008A7F35 + isa + PBXBuildFile + + 3EEA4F171BECDCD6008A7F35 + + fileRef + 3EEA4F111BECDCD6008A7F35 + isa + PBXBuildFile + + 3EEA4F181BECDCD6008A7F35 + + fileRef + 3EEA4F121BECDCD6008A7F35 + isa + PBXBuildFile + + 3EEA4F191BECDCD6008A7F35 + + fileRef + 3EEA4F131BECDCD6008A7F35 + isa + PBXBuildFile + + 3EEA4F1B1BECE358008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + LikesNode.h + sourceTree + <group> + + 3EEA4F1C1BECE358008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + LikesNode.m + sourceTree + <group> + + 3EEA4F1D1BECE358008A7F35 + + fileRef + 3EEA4F1C1BECE358008A7F35 + isa + PBXBuildFile + + 3EEA4F1E1BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_liked.png + sourceTree + <group> + + 3EEA4F1F1BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_liked@2x.png + sourceTree + <group> + + 3EEA4F201BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_liked@3x.png + sourceTree + <group> + + 3EEA4F241BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_like@3x.png + sourceTree + <group> + + 3EEA4F251BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_like@2x.png + sourceTree + <group> + + 3EEA4F261BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_like.png + sourceTree + <group> + + 3EEA4F271BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_comment@3x.png + sourceTree + <group> + + 3EEA4F281BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_comment@2x.png + sourceTree + <group> + + 3EEA4F291BECE440008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_comment.png + sourceTree + <group> + + 3EEA4F2A1BECE440008A7F35 + + fileRef + 3EEA4F1E1BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F2B1BECE440008A7F35 + + fileRef + 3EEA4F1F1BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F2C1BECE440008A7F35 + + fileRef + 3EEA4F201BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F301BECE440008A7F35 + + fileRef + 3EEA4F241BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F311BECE440008A7F35 + + fileRef + 3EEA4F251BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F321BECE440008A7F35 + + fileRef + 3EEA4F261BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F331BECE440008A7F35 + + fileRef + 3EEA4F271BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F341BECE440008A7F35 + + fileRef + 3EEA4F281BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F351BECE440008A7F35 + + fileRef + 3EEA4F291BECE440008A7F35 + isa + PBXBuildFile + + 3EEA4F361BECE775008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + CommentsNode.h + sourceTree + <group> + + 3EEA4F371BECE775008A7F35 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + CommentsNode.m + sourceTree + <group> + + 3EEA4F381BECE775008A7F35 + + fileRef + 3EEA4F371BECE775008A7F35 + isa + PBXBuildFile + + 3EEA4F391BECE99F008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_more.png + sourceTree + <group> + + 3EEA4F3A1BECE99F008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_more@2x.png + sourceTree + <group> + + 3EEA4F3B1BECE99F008A7F35 + + isa + PBXFileReference + lastKnownFileType + image.png + path + icon_more@3x.png + sourceTree + <group> + + 3EEA4F3C1BECE99F008A7F35 + + fileRef + 3EEA4F391BECE99F008A7F35 + isa + PBXBuildFile + + 3EEA4F3D1BECE99F008A7F35 + + fileRef + 3EEA4F3A1BECE99F008A7F35 + isa + PBXBuildFile + + 3EEA4F3E1BECE99F008A7F35 + + fileRef + 3EEA4F3B1BECE99F008A7F35 + isa + PBXBuildFile + + 7577801AA7321797C5FBB9A1 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods.a + sourceTree + BUILT_PRODUCTS_DIR + + 839964CA580D0ED921A6FCB1 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods.release.xcconfig + path + Pods/Target Support Files/Pods/Pods.release.xcconfig + sourceTree + <group> + + 842ADAFE88475D19B24183AC + + children + + E38AD915EE10CFC641F39E5C + 839964CA580D0ED921A6FCB1 + + isa + PBXGroup + name + Pods + sourceTree + <group> + + 852437589F1D53B9483A75DF + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Embed Pods Frameworks + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + "${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh" + + showEnvVarsInLog + 0 + + B5BD9E5609B2CB179EEE0CF4 + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Check Pods Manifest.lock + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null +if [[ $? != 0 ]] ; then + cat << EOM +error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. +EOM + exit 1 +fi + + showEnvVarsInLog + 0 + + E38AD915EE10CFC641F39E5C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods.debug.xcconfig + path + Pods/Target Support Files/Pods/Pods.debug.xcconfig + sourceTree + <group> + + EED34FA6D8171DF44757C852 + + children + + 7577801AA7321797C5FBB9A1 + + isa + PBXGroup + name + Frameworks + sourceTree + <group> + + + rootObject + 3EEA4EDC1BECC4A1008A7F35 + + diff --git a/examples/SocialAppLayout/Sample/AppDelegate.h b/examples/SocialAppLayout/Sample/AppDelegate.h index db4bc0a921..2aa29369b4 100644 --- a/examples/SocialAppLayout/Sample/AppDelegate.h +++ b/examples/SocialAppLayout/Sample/AppDelegate.h @@ -15,6 +15,4 @@ @property (strong, nonatomic) UIWindow *window; - @end - diff --git a/examples/SocialAppLayout/Sample/AppDelegate.m b/examples/SocialAppLayout/Sample/AppDelegate.m index 4b977d79e0..5bd8203ef3 100644 --- a/examples/SocialAppLayout/Sample/AppDelegate.m +++ b/examples/SocialAppLayout/Sample/AppDelegate.m @@ -10,23 +10,17 @@ */ #import "AppDelegate.h" - #import "ViewController.h" -@interface AppDelegate () - -@end - @implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]]; [self.window makeKeyAndVisible]; return YES; - } @end diff --git a/examples/SocialAppLayout/Sample/CommentsNode.m b/examples/SocialAppLayout/Sample/CommentsNode.m index c2f33d1219..1e8bc94028 100644 --- a/examples/SocialAppLayout/Sample/CommentsNode.m +++ b/examples/SocialAppLayout/Sample/CommentsNode.m @@ -20,8 +20,8 @@ @implementation CommentsNode -- (instancetype)initWithCommentsCount:(NSInteger)comentsCount { - +- (instancetype)initWithCommentsCount:(NSInteger)comentsCount +{ self = [super init]; if (self) { _commentsCount = comentsCount; @@ -44,8 +44,8 @@ } -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ ASStackLayoutSpec *mainStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:6.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:@[self.iconNode, self.countNode]]; // set sizeRange to make width fixed to 60 @@ -55,5 +55,4 @@ return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[mainStack]]; } - @end diff --git a/examples/SocialAppLayout/Sample/LikesNode.m b/examples/SocialAppLayout/Sample/LikesNode.m index b650398338..0a6eb9bc6a 100644 --- a/examples/SocialAppLayout/Sample/LikesNode.m +++ b/examples/SocialAppLayout/Sample/LikesNode.m @@ -21,8 +21,8 @@ @implementation LikesNode -- (instancetype)initWithLikesCount:(NSInteger)likesCount { - +- (instancetype)initWithLikesCount:(NSInteger)likesCount +{ self = [super init]; if (self) { _likesCount = likesCount; @@ -49,7 +49,7 @@ } -+ (BOOL) getYesOrNo ++ (BOOL)getYesOrNo { int tmp = (arc4random() % 30)+1; if (tmp % 5 == 0) { @@ -58,8 +58,8 @@ return NO; } -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ ASStackLayoutSpec *mainStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:6.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:@[_iconNode, _countNode]]; // set sizeRange to make width fixed to 60 @@ -67,7 +67,6 @@ ASRelativeSize max = ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(60.0), ASRelativeDimensionMakeWithPoints(40.0)); mainStack.sizeRange = ASRelativeSizeRangeMake(min, max); return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[mainStack]]; - } @end diff --git a/examples/SocialAppLayout/Sample/Post.m b/examples/SocialAppLayout/Sample/Post.m index 1e3b1fc183..7bedb4e25a 100644 --- a/examples/SocialAppLayout/Sample/Post.m +++ b/examples/SocialAppLayout/Sample/Post.m @@ -12,5 +12,4 @@ #import "Post.h" @implementation Post - @end diff --git a/examples/SocialAppLayout/Sample/PostNode.m b/examples/SocialAppLayout/Sample/PostNode.m index 9d29fcd4f3..fd570dc481 100644 --- a/examples/SocialAppLayout/Sample/PostNode.m +++ b/examples/SocialAppLayout/Sample/PostNode.m @@ -34,8 +34,8 @@ @implementation PostNode -- (instancetype)initWithPost:(Post *)post { - +- (instancetype)initWithPost:(Post *)post +{ self = [super init]; if (self) { _post = post; @@ -89,6 +89,7 @@ _postNode.userInteractionEnabled = YES; _postNode.linkAttributeNames = @[ kLinkAttributeName ]; _postNode.attributedString = attrString; + _postNode.passthroughNonlinkTouches = YES; // passes touches through when they aren't on a link } @@ -180,14 +181,19 @@ [super didLoad]; } -- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ // Flexible spacer between username and time ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init]; spacer.flexGrow = YES; - + + // NOTE: This inset is not actually required by the layout, but is an example of the upward propogation of layoutable + // properties. Specifically, .flexGrow from the child is transferred to the inset spec so they can expand together. + // Without this capability, it would be required to set insetSpacer.flexGrow = YES; + ASInsetLayoutSpec *insetSpacer = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(0, 0, 0, 0) child:spacer]; + // Horizontal stack for name, username, via icon and time - NSMutableArray *layoutSpecChildren = [@[_nameNode, _usernameNode, spacer] mutableCopy]; + NSMutableArray *layoutSpecChildren = [@[_nameNode, _usernameNode, insetSpacer] mutableCopy]; if (_post.via != 0) { [layoutSpecChildren addObject:_viaNode]; } diff --git a/examples/SocialAppLayout/Sample/TextStyles.m b/examples/SocialAppLayout/Sample/TextStyles.m index 153b12407e..cc2b6bdffb 100644 --- a/examples/SocialAppLayout/Sample/TextStyles.m +++ b/examples/SocialAppLayout/Sample/TextStyles.m @@ -54,16 +54,16 @@ }; } -+ (NSDictionary *)cellControlStyle { - ++ (NSDictionary *)cellControlStyle +{ return @{ NSFontAttributeName : [UIFont systemFontOfSize:13.0], NSForegroundColorAttributeName: [UIColor lightGrayColor] }; } -+ (NSDictionary *)cellControlColoredStyle { - ++ (NSDictionary *)cellControlColoredStyle +{ return @{ NSFontAttributeName : [UIFont systemFontOfSize:13.0], NSForegroundColorAttributeName: [UIColor colorWithRed:59.0/255.0 green:89.0/255.0 blue:152.0/255.0 alpha:1.0] diff --git a/examples/SocialAppLayout/Sample/ViewController.h b/examples/SocialAppLayout/Sample/ViewController.h index 7352ff1109..76b893d103 100644 --- a/examples/SocialAppLayout/Sample/ViewController.h +++ b/examples/SocialAppLayout/Sample/ViewController.h @@ -12,7 +12,4 @@ #import @interface ViewController : UIViewController - - @end - diff --git a/examples/SocialAppLayout/Sample/ViewController.m b/examples/SocialAppLayout/Sample/ViewController.m index cbda71e3ab..c9500b1778 100644 --- a/examples/SocialAppLayout/Sample/ViewController.m +++ b/examples/SocialAppLayout/Sample/ViewController.m @@ -45,8 +45,8 @@ _tableView.asyncDelegate = nil; } -- (void)viewDidLoad { - +- (void)viewDidLoad +{ [super viewDidLoad]; self.tableView = [[ASTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain asyncDataFetching:YES]; @@ -57,8 +57,8 @@ [self.view addSubview:self.tableView]; } -- (void)createSocialAppDataSource { - +- (void)createSocialAppDataSource +{ _socialAppDataSource = [[NSMutableArray alloc] init]; Post *newPost = [[Post alloc] init];