diff --git a/.github/workflows/ci-master-only.yml b/.github/workflows/ci-master-only.yml index c7a1110a2..b2df79192 100644 --- a/.github/workflows/ci-master-only.yml +++ b/.github/workflows/ci-master-only.yml @@ -8,7 +8,7 @@ on: jobs: cocoapods-lint: env: - DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.4.0.app/Contents/Developer name: Verify that podspec lints runs-on: macos-latest steps: diff --git a/.github/workflows/ci-pull-requests-only.yml b/.github/workflows/ci-pull-requests-only.yml index 5fb368222..791c638cf 100644 --- a/.github/workflows/ci-pull-requests-only.yml +++ b/.github/workflows/ci-pull-requests-only.yml @@ -8,7 +8,7 @@ on: jobs: buildsh: env: - DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.4.0.app/Contents/Developer strategy: matrix: mode: [cocoapods-lint-default-subspecs, cocoapods-lint-other-subspecs] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 885175a10..0c8164a93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: buildsh: env: - DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.4.0.app/Contents/Developer strategy: matrix: mode: [tests, framework, life-without-cocoapods, carthage, examples-pt1, examples-pt2, examples-pt3, examples-pt4] diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 06a68f8a8..5c6a98031 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -236,6 +236,8 @@ 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */; }; 9F98C0261DBE29E000476D92 /* ASControlTargetAction.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */; }; 9F98C0271DBE29FC00476D92 /* ASControlTargetAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A14F82AE2DD57B1E00A9147D /* ASDefaultImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A14F82AC2DD57B1E00A9147D /* ASDefaultImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A14F82AF2DD57B1E00A9147D /* ASDefaultImageDownloader.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14F82AD2DD57B1E00A9147D /* ASDefaultImageDownloader.mm */; }; A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = A373200E1C571B050011FC94 /* ASTextNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; AC026B581BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */; }; AC026B701BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -814,6 +816,8 @@ 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionViewTests.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASControlTargetAction.h; sourceTree = ""; }; 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASControlTargetAction.mm; sourceTree = ""; }; + A14F82AC2DD57B1E00A9147D /* ASDefaultImageDownloader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASDefaultImageDownloader.h; sourceTree = ""; }; + A14F82AD2DD57B1E00A9147D /* ASDefaultImageDownloader.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDefaultImageDownloader.mm; sourceTree = ""; }; A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitFontSizeAdjuster.h; path = TextKit/ASTextKitFontSizeAdjuster.h; sourceTree = ""; }; A373200E1C571B050011FC94 /* ASTextNode+Beta.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ASTextNode+Beta.h"; sourceTree = ""; }; AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASAbsoluteLayoutSpecSnapshotTests.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; @@ -1217,6 +1221,8 @@ 058D09D6195D050800B7D73C /* ASControlNode.mm */, 058D09D7195D050800B7D73C /* ASControlNode+Subclasses.h */, 058D09D8195D050800B7D73C /* ASDisplayNode.h */, + A14F82AC2DD57B1E00A9147D /* ASDefaultImageDownloader.h */, + A14F82AD2DD57B1E00A9147D /* ASDefaultImageDownloader.mm */, 058D09D9195D050800B7D73C /* ASDisplayNode.mm */, CC6AA2D81E9F03B900978E87 /* ASDisplayNode+Ancestry.h */, CC6AA2D91E9F03B900978E87 /* ASDisplayNode+Ancestry.mm */, @@ -1964,6 +1970,7 @@ ACE87A2C1D73696800D7FF06 /* ASSectionContext.h in Headers */, 509E68631B3AEDB4009B9150 /* ASCollectionViewLayoutController.h in Headers */, B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */, + A14F82AE2DD57B1E00A9147D /* ASDefaultImageDownloader.h in Headers */, 67A75CA42C5412F1003AFD51 /* ASCollectionView+Undeprecated.h in Headers */, 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */, CC56013B1F06E9A700DC4FBE /* ASIntegerMap.h in Headers */, @@ -2518,6 +2525,7 @@ DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */, CCEDDDD1200C488000FFCD0A /* ASConfiguration.mm in Sources */, 254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.mm in Sources */, + A14F82AF2DD57B1E00A9147D /* ASDefaultImageDownloader.mm in Sources */, E5E2D7301EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm in Sources */, 34EFC76B1B701CEB00AD841F /* ASLayoutSpec.mm in Sources */, CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */, diff --git a/Source/ASDefaultImageDownloader.h b/Source/ASDefaultImageDownloader.h new file mode 100644 index 000000000..c2311be3f --- /dev/null +++ b/Source/ASDefaultImageDownloader.h @@ -0,0 +1,27 @@ +// +// ASDefaultImageDownloader.h +// Texture +// +// Created by Andrew Finnell on 5/14/25. +// Copyright © 2025 Pinterest. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef id_Nullable(^ASImageDownloaderProvider)(void); +typedef id_Nullable(^ASImageCacheProvider)(void); + +@interface ASDefaultImageDownloader : NSObject + ++ (nullable id)defaultDownloader; ++ (nullable id)defaultCache; + ++ (void)setDefaultDownloaderProvider:(ASImageDownloaderProvider _Nonnull)downloaderProvider + cacheProvider:(ASImageCacheProvider _Nonnull)cacheProvider; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/ASDefaultImageDownloader.mm b/Source/ASDefaultImageDownloader.mm new file mode 100644 index 000000000..f0018c4f3 --- /dev/null +++ b/Source/ASDefaultImageDownloader.mm @@ -0,0 +1,100 @@ +// +// ASDefaultImageDownloader.m +// Texture +// +// Created by Andrew Finnell on 5/14/25. +// Copyright © 2025 Pinterest. All rights reserved. +// + +#import "ASDefaultImageDownloader.h" +#import +#import +#if AS_PIN_REMOTE_IMAGE +#import +#endif + +using AS::MutexLocker; + +@interface ASDefaultImageDownloader () { + AS::Mutex *_lock; + ASImageDownloaderProvider _downloaderProvider; + ASImageCacheProvider _cacheProvider; +} + ++ (instancetype)sharedInstance; + +@end + +@implementation ASDefaultImageDownloader + +- (instancetype)init +{ + self = [super init]; + if (self != nil) { + _lock = new AS::Mutex(); + _downloaderProvider = ^id(void) { +#if AS_PIN_REMOTE_IMAGE + return [ASPINRemoteImageDownloader sharedDownloader]; +#else + return [ASBasicImageDownloader sharedImageDownloader]; +#endif + }; + _cacheProvider = ^id(void) { +#if AS_PIN_REMOTE_IMAGE + return [ASPINRemoteImageDownloader sharedDownloader]; +#else + return nil; +#endif + }; + } + return self; +} + ++ (instancetype)sharedInstance; +{ + static dispatch_once_t onceToken; + static ASDefaultImageDownloader *sharedInstance = nil; + dispatch_once(&onceToken, ^{ + sharedInstance = [[ASDefaultImageDownloader alloc] init]; + }); + return sharedInstance; +} + +- (nullable id)defaultDownloader +{ + MutexLocker l(*self->_lock); + return self->_downloaderProvider(); +} + +- (nullable id)defaultCache +{ + MutexLocker l(*self->_lock); + return self->_cacheProvider(); +} + +- (void)setDefaultDownloaderProvider:(ASImageDownloaderProvider _Nonnull)downloaderProvider + cacheProvider:(ASImageCacheProvider _Nonnull)cacheProvider +{ + MutexLocker l(*self->_lock); + _downloaderProvider = [downloaderProvider copy]; + _cacheProvider = [cacheProvider copy]; +} + ++ (nullable id)defaultDownloader +{ + return [[ASDefaultImageDownloader sharedInstance] defaultDownloader]; +} + ++ (nullable id)defaultCache +{ + return [[ASDefaultImageDownloader sharedInstance] defaultCache]; +} + ++ (void)setDefaultDownloaderProvider:(ASImageDownloaderProvider _Nonnull)downloaderProvider + cacheProvider:(ASImageCacheProvider _Nonnull)cacheProvider +{ + [[ASDefaultImageDownloader sharedInstance] setDefaultDownloaderProvider:downloaderProvider + cacheProvider:cacheProvider]; +} + +@end diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index 750aba952..382dcd1b5 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -25,11 +25,7 @@ #import #endif -#if AS_PIN_REMOTE_IMAGE -#import -#else -#import -#endif +#import using AS::MutexLocker; @@ -190,11 +186,7 @@ - (instancetype)initWithCache:(id)cache downloader:(id -#import #import #import #import @@ -19,10 +18,7 @@ #import #import #import - -#if AS_PIN_REMOTE_IMAGE -#import -#endif +#import @interface ASNetworkImageNode () { @@ -111,11 +107,7 @@ - (instancetype)initWithCache:(id)cache downloader:(id #import #import +#import diff --git a/Source/Details/ASImageProtocols.h b/Source/Details/ASImageProtocols.h index 91a0d579f..e1b40fe9e 100644 --- a/Source/Details/ASImageProtocols.h +++ b/Source/Details/ASImageProtocols.h @@ -25,7 +25,7 @@ typedef NS_ENUM(NSInteger, ASImageCacheType) { ASImageCacheTypeSynchronous, }; -typedef void(^ASImageCacherCompletion)(id _Nullable imageFromCache, ASImageCacheType cacheType); +typedef void(^ASImageCacherCompletion)(id _Nullable imageFromCache, ASImageCacheType cacheType) NS_SWIFT_SENDABLE; @protocol ASImageCacheProtocol @@ -71,12 +71,12 @@ typedef void(^ASImageCacherCompletion)(id _Nullable i @param downloadIdentifier The identifier for the download task that completed. @param userInfo Any additional info that your downloader would like to communicate through Texture. */ -typedef void(^ASImageDownloaderCompletion)(id _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo); +typedef void(^ASImageDownloaderCompletion)(id _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo) NS_SWIFT_SENDABLE; /** @param progress The progress of the download, in the range of (0.0, 1.0), inclusive. */ -typedef void(^ASImageDownloaderProgress)(CGFloat progress); +typedef void(^ASImageDownloaderProgress)(CGFloat progress) NS_SWIFT_SENDABLE; typedef void(^ASImageDownloaderProgressImage)(UIImage *progressImage, CGFloat progress, id _Nullable downloadIdentifier); typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) { @@ -197,7 +197,7 @@ withDownloadIdentifier:(id)downloadIdentifier; /** @abstract Return the objects's cover image. */ -@property (nonatomic, readonly) UIImage *coverImage; +@property (nonatomic, readonly, nullable) UIImage *coverImage; /** @abstract Return a boolean to indicate that the cover image is ready. */ @@ -225,16 +225,16 @@ withDownloadIdentifier:(id)downloadIdentifier; /** @abstract Return any error that has occured. Playback will be paused if this returns non-nil. */ -@property (nonatomic, readonly) NSError *error; +@property (nonatomic, readonly, nullable) NSError *error; /** @abstract Should be called when playback is ready. */ -@property (nonatomic) dispatch_block_t playbackReadyCallback; +@property (nonatomic, nullable) dispatch_block_t playbackReadyCallback NS_SWIFT_SENDABLE; /** @abstract Return the image at a given index. */ -- (CGImageRef)imageAtIndex:(NSUInteger)index; +- (nullable CGImageRef)imageAtIndex:(NSUInteger)index; /** @abstract Return the duration at a given index. */ diff --git a/build.sh b/build.sh index 90242b8e3..37e34a523 100755 --- a/build.sh +++ b/build.sh @@ -9,8 +9,8 @@ # echo ************* diagnostics end # run this on a 2x device until we've updated snapshot images to 3x -PLATFORM="${TEXTURE_BUILD_PLATFORM:-platform=iOS Simulator,OS=17.4,name=iPhone SE (3rd generation)}" -SDK="${TEXTURE_BUILD_SDK:-iphonesimulator17.4}" +PLATFORM="${TEXTURE_BUILD_PLATFORM:-platform=iOS Simulator,OS=18.5,name=iPhone SE (3rd generation)}" +SDK="${TEXTURE_BUILD_SDK:-iphonesimulator18.5}" DERIVED_DATA_PATH="~/ASDKDerivedData" # It is pitch black.