Skip to content

Commit e696302

Browse files
authored
Add default image provider (#2127)
* Add default image provider ## Summary Right now image nodes hardcode logic to use either PINRemoteImage or the basic image downloader. Additionally, Texture is missing annotations for nullability and sendable for several of the image blocks and types. Introduce ASDefaultImageDownloader as a singleton. It takes blocks to return the default image downloader and image cache. Update both image nodes to use this. By default ASDefaultImageDownloader uses the same logic the image nodes used to, so change in behavior. ## Test plan Run the Kittens example and verify it works. * Appears we need Xcode 16.4 * And need at least 18.5
1 parent 5d75e12 commit e696302

File tree

11 files changed

+152
-32
lines changed

11 files changed

+152
-32
lines changed

.github/workflows/ci-master-only.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
jobs:
99
cocoapods-lint:
1010
env:
11-
DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer
11+
DEVELOPER_DIR: /Applications/Xcode_16.4.0.app/Contents/Developer
1212
name: Verify that podspec lints
1313
runs-on: macos-latest
1414
steps:

.github/workflows/ci-pull-requests-only.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
jobs:
99
buildsh:
1010
env:
11-
DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer
11+
DEVELOPER_DIR: /Applications/Xcode_16.4.0.app/Contents/Developer
1212
strategy:
1313
matrix:
1414
mode: [cocoapods-lint-default-subspecs, cocoapods-lint-other-subspecs]

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on: [push, pull_request]
55
jobs:
66
buildsh:
77
env:
8-
DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer
8+
DEVELOPER_DIR: /Applications/Xcode_16.4.0.app/Contents/Developer
99
strategy:
1010
matrix:
1111
mode: [tests, framework, life-without-cocoapods, carthage, examples-pt1, examples-pt2, examples-pt3, examples-pt4]

AsyncDisplayKit.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@
236236
9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */; };
237237
9F98C0261DBE29E000476D92 /* ASControlTargetAction.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */; };
238238
9F98C0271DBE29FC00476D92 /* ASControlTargetAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
239+
A14F82AE2DD57B1E00A9147D /* ASDefaultImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A14F82AC2DD57B1E00A9147D /* ASDefaultImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; };
240+
A14F82AF2DD57B1E00A9147D /* ASDefaultImageDownloader.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14F82AD2DD57B1E00A9147D /* ASDefaultImageDownloader.mm */; };
239241
A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = A373200E1C571B050011FC94 /* ASTextNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; };
240242
AC026B581BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */; };
241243
AC026B701BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -814,6 +816,8 @@
814816
9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionViewTests.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
815817
9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASControlTargetAction.h; sourceTree = "<group>"; };
816818
9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASControlTargetAction.mm; sourceTree = "<group>"; };
819+
A14F82AC2DD57B1E00A9147D /* ASDefaultImageDownloader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASDefaultImageDownloader.h; sourceTree = "<group>"; };
820+
A14F82AD2DD57B1E00A9147D /* ASDefaultImageDownloader.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDefaultImageDownloader.mm; sourceTree = "<group>"; };
817821
A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitFontSizeAdjuster.h; path = TextKit/ASTextKitFontSizeAdjuster.h; sourceTree = "<group>"; };
818822
A373200E1C571B050011FC94 /* ASTextNode+Beta.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ASTextNode+Beta.h"; sourceTree = "<group>"; };
819823
AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASAbsoluteLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
@@ -1217,6 +1221,8 @@
12171221
058D09D6195D050800B7D73C /* ASControlNode.mm */,
12181222
058D09D7195D050800B7D73C /* ASControlNode+Subclasses.h */,
12191223
058D09D8195D050800B7D73C /* ASDisplayNode.h */,
1224+
A14F82AC2DD57B1E00A9147D /* ASDefaultImageDownloader.h */,
1225+
A14F82AD2DD57B1E00A9147D /* ASDefaultImageDownloader.mm */,
12201226
058D09D9195D050800B7D73C /* ASDisplayNode.mm */,
12211227
CC6AA2D81E9F03B900978E87 /* ASDisplayNode+Ancestry.h */,
12221228
CC6AA2D91E9F03B900978E87 /* ASDisplayNode+Ancestry.mm */,
@@ -1964,6 +1970,7 @@
19641970
ACE87A2C1D73696800D7FF06 /* ASSectionContext.h in Headers */,
19651971
509E68631B3AEDB4009B9150 /* ASCollectionViewLayoutController.h in Headers */,
19661972
B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */,
1973+
A14F82AE2DD57B1E00A9147D /* ASDefaultImageDownloader.h in Headers */,
19671974
67A75CA42C5412F1003AFD51 /* ASCollectionView+Undeprecated.h in Headers */,
19681975
68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */,
19691976
CC56013B1F06E9A700DC4FBE /* ASIntegerMap.h in Headers */,
@@ -2518,6 +2525,7 @@
25182525
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */,
25192526
CCEDDDD1200C488000FFCD0A /* ASConfiguration.mm in Sources */,
25202527
254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.mm in Sources */,
2528+
A14F82AF2DD57B1E00A9147D /* ASDefaultImageDownloader.mm in Sources */,
25212529
E5E2D7301EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm in Sources */,
25222530
34EFC76B1B701CEB00AD841F /* ASLayoutSpec.mm in Sources */,
25232531
CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */,

Source/ASDefaultImageDownloader.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// ASDefaultImageDownloader.h
3+
// Texture
4+
//
5+
// Created by Andrew Finnell on 5/14/25.
6+
// Copyright © 2025 Pinterest. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import <AsyncDisplayKit/ASImageProtocols.h>
11+
12+
NS_ASSUME_NONNULL_BEGIN
13+
14+
typedef id<ASImageDownloaderProtocol>_Nullable(^ASImageDownloaderProvider)(void);
15+
typedef id<ASImageCacheProtocol>_Nullable(^ASImageCacheProvider)(void);
16+
17+
@interface ASDefaultImageDownloader : NSObject
18+
19+
+ (nullable id<ASImageDownloaderProtocol>)defaultDownloader;
20+
+ (nullable id<ASImageCacheProtocol>)defaultCache;
21+
22+
+ (void)setDefaultDownloaderProvider:(ASImageDownloaderProvider _Nonnull)downloaderProvider
23+
cacheProvider:(ASImageCacheProvider _Nonnull)cacheProvider;
24+
25+
@end
26+
27+
NS_ASSUME_NONNULL_END

Source/ASDefaultImageDownloader.mm

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// ASDefaultImageDownloader.m
3+
// Texture
4+
//
5+
// Created by Andrew Finnell on 5/14/25.
6+
// Copyright © 2025 Pinterest. All rights reserved.
7+
//
8+
9+
#import "ASDefaultImageDownloader.h"
10+
#import <AsyncDisplayKit/ASThread.h>
11+
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
12+
#if AS_PIN_REMOTE_IMAGE
13+
#import <AsyncDisplayKit/ASPINRemoteImageDownloader.h>
14+
#endif
15+
16+
using AS::MutexLocker;
17+
18+
@interface ASDefaultImageDownloader () {
19+
AS::Mutex *_lock;
20+
ASImageDownloaderProvider _downloaderProvider;
21+
ASImageCacheProvider _cacheProvider;
22+
}
23+
24+
+ (instancetype)sharedInstance;
25+
26+
@end
27+
28+
@implementation ASDefaultImageDownloader
29+
30+
- (instancetype)init
31+
{
32+
self = [super init];
33+
if (self != nil) {
34+
_lock = new AS::Mutex();
35+
_downloaderProvider = ^id<ASImageDownloaderProtocol>(void) {
36+
#if AS_PIN_REMOTE_IMAGE
37+
return [ASPINRemoteImageDownloader sharedDownloader];
38+
#else
39+
return [ASBasicImageDownloader sharedImageDownloader];
40+
#endif
41+
};
42+
_cacheProvider = ^id<ASImageCacheProtocol>(void) {
43+
#if AS_PIN_REMOTE_IMAGE
44+
return [ASPINRemoteImageDownloader sharedDownloader];
45+
#else
46+
return nil;
47+
#endif
48+
};
49+
}
50+
return self;
51+
}
52+
53+
+ (instancetype)sharedInstance;
54+
{
55+
static dispatch_once_t onceToken;
56+
static ASDefaultImageDownloader *sharedInstance = nil;
57+
dispatch_once(&onceToken, ^{
58+
sharedInstance = [[ASDefaultImageDownloader alloc] init];
59+
});
60+
return sharedInstance;
61+
}
62+
63+
- (nullable id<ASImageDownloaderProtocol>)defaultDownloader
64+
{
65+
MutexLocker l(*self->_lock);
66+
return self->_downloaderProvider();
67+
}
68+
69+
- (nullable id<ASImageCacheProtocol>)defaultCache
70+
{
71+
MutexLocker l(*self->_lock);
72+
return self->_cacheProvider();
73+
}
74+
75+
- (void)setDefaultDownloaderProvider:(ASImageDownloaderProvider _Nonnull)downloaderProvider
76+
cacheProvider:(ASImageCacheProvider _Nonnull)cacheProvider
77+
{
78+
MutexLocker l(*self->_lock);
79+
_downloaderProvider = [downloaderProvider copy];
80+
_cacheProvider = [cacheProvider copy];
81+
}
82+
83+
+ (nullable id<ASImageDownloaderProtocol>)defaultDownloader
84+
{
85+
return [[ASDefaultImageDownloader sharedInstance] defaultDownloader];
86+
}
87+
88+
+ (nullable id<ASImageCacheProtocol>)defaultCache
89+
{
90+
return [[ASDefaultImageDownloader sharedInstance] defaultCache];
91+
}
92+
93+
+ (void)setDefaultDownloaderProvider:(ASImageDownloaderProvider _Nonnull)downloaderProvider
94+
cacheProvider:(ASImageCacheProvider _Nonnull)cacheProvider
95+
{
96+
[[ASDefaultImageDownloader sharedInstance] setDefaultDownloaderProvider:downloaderProvider
97+
cacheProvider:cacheProvider];
98+
}
99+
100+
@end

Source/ASMultiplexImageNode.mm

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@
2525
#import <AsyncDisplayKit/ASPhotosFrameworkImageRequest.h>
2626
#endif
2727

28-
#if AS_PIN_REMOTE_IMAGE
29-
#import <AsyncDisplayKit/ASPINRemoteImageDownloader.h>
30-
#else
31-
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
32-
#endif
28+
#import <AsyncDisplayKit/ASDefaultImageDownloader.h>
3329

3430
using AS::MutexLocker;
3531

@@ -190,11 +186,7 @@ - (instancetype)initWithCache:(id<ASImageCacheProtocol>)cache downloader:(id<ASI
190186

191187
- (instancetype)init
192188
{
193-
#if AS_PIN_REMOTE_IMAGE
194-
return [self initWithCache:[ASPINRemoteImageDownloader sharedDownloader] downloader:[ASPINRemoteImageDownloader sharedDownloader]];
195-
#else
196-
return [self initWithCache:nil downloader:[ASBasicImageDownloader sharedImageDownloader]];
197-
#endif
189+
return [self initWithCache:[ASDefaultImageDownloader defaultCache] downloader:[ASDefaultImageDownloader defaultDownloader]];
198190
}
199191

200192
- (void)dealloc

Source/ASNetworkImageNode.mm

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
#import <AsyncDisplayKit/ASNetworkImageNode.h>
1111

12-
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
1312
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
1413
#import <AsyncDisplayKit/ASDisplayNodeInternal.h>
1514
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
@@ -19,10 +18,7 @@
1918
#import <AsyncDisplayKit/ASImageNode+AnimatedImagePrivate.h>
2019
#import <AsyncDisplayKit/ASImageContainerProtocolCategories.h>
2120
#import <AsyncDisplayKit/ASNetworkImageLoadInfo+Private.h>
22-
23-
#if AS_PIN_REMOTE_IMAGE
24-
#import <AsyncDisplayKit/ASPINRemoteImageDownloader.h>
25-
#endif
21+
#import <AsyncDisplayKit/ASDefaultImageDownloader.h>
2622

2723
@interface ASNetworkImageNode ()
2824
{
@@ -111,11 +107,7 @@ - (instancetype)initWithCache:(id<ASImageCacheProtocol>)cache downloader:(id<ASI
111107

112108
- (instancetype)init
113109
{
114-
#if AS_PIN_REMOTE_IMAGE
115-
return [self initWithCache:[ASPINRemoteImageDownloader sharedDownloader] downloader:[ASPINRemoteImageDownloader sharedDownloader]];
116-
#else
117-
return [self initWithCache:nil downloader:[ASBasicImageDownloader sharedImageDownloader]];
118-
#endif
110+
return [self initWithCache:[ASDefaultImageDownloader defaultCache] downloader:[ASDefaultImageDownloader defaultDownloader]];
119111
}
120112

121113
- (void)dealloc

Source/AsyncDisplayKit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,4 @@
127127
#import <AsyncDisplayKit/_ASDisplayLayer.h>
128128
#import <AsyncDisplayKit/_ASDisplayView.h>
129129
#import <AsyncDisplayKit/_ASTransitionContext.h>
130+
#import <AsyncDisplayKit/ASDefaultImageDownloader.h>

Source/Details/ASImageProtocols.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ typedef NS_ENUM(NSInteger, ASImageCacheType) {
2525
ASImageCacheTypeSynchronous,
2626
};
2727

28-
typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable imageFromCache, ASImageCacheType cacheType);
28+
typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable imageFromCache, ASImageCacheType cacheType) NS_SWIFT_SENDABLE;
2929

3030
@protocol ASImageCacheProtocol <NSObject>
3131

@@ -71,12 +71,12 @@ typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable i
7171
@param downloadIdentifier The identifier for the download task that completed.
7272
@param userInfo Any additional info that your downloader would like to communicate through Texture.
7373
*/
74-
typedef void(^ASImageDownloaderCompletion)(id <ASImageContainerProtocol> _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo);
74+
typedef void(^ASImageDownloaderCompletion)(id <ASImageContainerProtocol> _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo) NS_SWIFT_SENDABLE;
7575

7676
/**
7777
@param progress The progress of the download, in the range of (0.0, 1.0), inclusive.
7878
*/
79-
typedef void(^ASImageDownloaderProgress)(CGFloat progress);
79+
typedef void(^ASImageDownloaderProgress)(CGFloat progress) NS_SWIFT_SENDABLE;
8080
typedef void(^ASImageDownloaderProgressImage)(UIImage *progressImage, CGFloat progress, id _Nullable downloadIdentifier);
8181

8282
typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) {
@@ -197,7 +197,7 @@ withDownloadIdentifier:(id)downloadIdentifier;
197197
/**
198198
@abstract Return the objects's cover image.
199199
*/
200-
@property (nonatomic, readonly) UIImage *coverImage;
200+
@property (nonatomic, readonly, nullable) UIImage *coverImage;
201201
/**
202202
@abstract Return a boolean to indicate that the cover image is ready.
203203
*/
@@ -225,16 +225,16 @@ withDownloadIdentifier:(id)downloadIdentifier;
225225
/**
226226
@abstract Return any error that has occured. Playback will be paused if this returns non-nil.
227227
*/
228-
@property (nonatomic, readonly) NSError *error;
228+
@property (nonatomic, readonly, nullable) NSError *error;
229229
/**
230230
@abstract Should be called when playback is ready.
231231
*/
232-
@property (nonatomic) dispatch_block_t playbackReadyCallback;
232+
@property (nonatomic, nullable) dispatch_block_t playbackReadyCallback NS_SWIFT_SENDABLE;
233233

234234
/**
235235
@abstract Return the image at a given index.
236236
*/
237-
- (CGImageRef)imageAtIndex:(NSUInteger)index;
237+
- (nullable CGImageRef)imageAtIndex:(NSUInteger)index;
238238
/**
239239
@abstract Return the duration at a given index.
240240
*/

0 commit comments

Comments
 (0)