Skip to content

Commit c392689

Browse files
sammy-SCosdnk
authored andcommitted
Introducing RCTBlockingImageManager, an image manager for tests in Fabric
Summary: Changelog: [Internal] This allows to block queue until image is fetched. In paper, the photo of dog will not appear unless the network request is "fast enough". {F228670428} Reviewed By: shergin Differential Revision: D19907906 fbshipit-source-id: 98d68abf1255388f9b97fb9da367d8f583a4220d
1 parent 0b059d9 commit c392689

File tree

5 files changed

+150
-5
lines changed

5 files changed

+150
-5
lines changed

ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
#include "ImageManager.h"
99

1010
#import <React/RCTImageLoaderWithAttributionProtocol.h>
11+
#import <React/RCTUtils.h>
1112
#import <react/utils/ManagedObjectWrapper.h>
1213

1314
#import "RCTImageManager.h"
15+
#import "RCTSyncImageManager.h"
1416

1517
namespace facebook {
1618
namespace react {
@@ -20,7 +22,11 @@
2022
id<RCTImageLoaderWithAttributionProtocol> imageLoader =
2123
(id<RCTImageLoaderWithAttributionProtocol>)unwrapManagedObject(
2224
contextContainer->at<std::shared_ptr<void>>("RCTImageLoader"));
23-
self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:imageLoader];
25+
if (RCTRunningInTestEnvironment()) {
26+
self_ = (__bridge_retained void *)[[RCTSyncImageManager alloc] initWithImageLoader:imageLoader];
27+
} else {
28+
self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:imageLoader];
29+
}
2430
}
2531

2632
ImageManager::~ImageManager()

ReactCommon/fabric/imagemanager/platform/ios/RCTImageManager.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
#import <UIKit/UIKit.h>
99

10-
#import <react/core/ReactPrimitives.h>
11-
#import <react/imagemanager/ImageRequest.h>
12-
#import <react/imagemanager/primitives.h>
10+
#import <RCTImageManagerProtocol.h>
1311

1412
NS_ASSUME_NONNULL_BEGIN
1513

@@ -18,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
1816
/**
1917
* iOS-specific ImageManager.
2018
*/
21-
@interface RCTImageManager : NSObject
19+
@interface RCTImageManager : NSObject <RCTImageManagerProtocol>
2220

2321
- (instancetype)initWithImageLoader:(id<RCTImageLoaderWithAttributionProtocol>)imageLoader;
2422

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <Foundation/Foundation.h>
9+
#import <react/core/ReactPrimitives.h>
10+
#import <react/imagemanager/ImageRequest.h>
11+
12+
@protocol RCTImageManagerProtocol <NSObject>
13+
14+
- (facebook::react::ImageRequest)requestImage:(facebook::react::ImageSource)imageSource
15+
surfaceId:(facebook::react::SurfaceId)surfaceId;
16+
@end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <UIKit/UIKit.h>
9+
10+
#import <RCTImageManagerProtocol.h>
11+
12+
NS_ASSUME_NONNULL_BEGIN
13+
14+
@protocol RCTImageLoaderWithAttributionProtocol;
15+
16+
/**
17+
* iOS-specific ImageManager.
18+
*/
19+
@interface RCTSyncImageManager : NSObject <RCTImageManagerProtocol>
20+
21+
- (instancetype)initWithImageLoader:(id<RCTImageLoaderWithAttributionProtocol>)imageLoader;
22+
23+
- (facebook::react::ImageRequest)requestImage:(facebook::react::ImageSource)imageSource
24+
surfaceId:(facebook::react::SurfaceId)surfaceId;
25+
26+
@end
27+
28+
NS_ASSUME_NONNULL_END
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import "RCTSyncImageManager.h"
9+
10+
#import <react/utils/ManagedObjectWrapper.h>
11+
#import <react/utils/SharedFunction.h>
12+
13+
#import <React/RCTAssert.h>
14+
#import <React/RCTImageLoaderWithAttributionProtocol.h>
15+
#import <React/RCTLog.h>
16+
#import <react/imagemanager/ImageResponse.h>
17+
#import <react/imagemanager/ImageResponseObserver.h>
18+
19+
#import "RCTImagePrimitivesConversions.h"
20+
21+
using namespace facebook::react;
22+
23+
@implementation RCTSyncImageManager {
24+
id<RCTImageLoaderWithAttributionProtocol> _imageLoader;
25+
}
26+
27+
- (instancetype)initWithImageLoader:(id<RCTImageLoaderWithAttributionProtocol>)imageLoader
28+
{
29+
if (self = [super init]) {
30+
RCTAssert(RCTRunningInTestEnvironment(), @"This class is only meant to be used in test environment");
31+
_imageLoader = imageLoader;
32+
}
33+
34+
return self;
35+
}
36+
37+
- (ImageRequest)requestImage:(ImageSource)imageSource surfaceId:(SurfaceId)surfaceId
38+
{
39+
auto imageRequest = ImageRequest(imageSource, nullptr);
40+
auto weakObserverCoordinator =
41+
(std::weak_ptr<const ImageResponseObserverCoordinator>)imageRequest.getSharedObserverCoordinator();
42+
43+
auto sharedCancelationFunction = SharedFunction<>();
44+
imageRequest.setCancelationFunction(sharedCancelationFunction);
45+
46+
dispatch_group_t imageWaitGroup = dispatch_group_create();
47+
48+
dispatch_group_enter(imageWaitGroup);
49+
50+
NSURLRequest *request = NSURLRequestFromImageSource(imageSource);
51+
52+
auto completionBlock = ^(NSError *error, UIImage *image) {
53+
auto observerCoordinator = weakObserverCoordinator.lock();
54+
if (!observerCoordinator) {
55+
return;
56+
}
57+
58+
if (image && !error) {
59+
observerCoordinator->nativeImageResponseComplete(ImageResponse(wrapManagedObject(image)));
60+
} else {
61+
observerCoordinator->nativeImageResponseFailed();
62+
}
63+
dispatch_group_leave(imageWaitGroup);
64+
};
65+
66+
auto progressBlock = ^(int64_t progress, int64_t total) {
67+
auto observerCoordinator = weakObserverCoordinator.lock();
68+
if (!observerCoordinator) {
69+
return;
70+
}
71+
72+
observerCoordinator->nativeImageResponseProgress(progress / (float)total);
73+
};
74+
75+
RCTImageURLLoaderRequest *loaderRequest =
76+
[self->_imageLoader loadImageWithURLRequest:request
77+
size:CGSizeMake(imageSource.size.width, imageSource.size.height)
78+
scale:imageSource.scale
79+
clipped:YES
80+
resizeMode:RCTResizeModeStretch
81+
attribution:{
82+
.surfaceId = surfaceId,
83+
}
84+
progressBlock:progressBlock
85+
partialLoadBlock:nil
86+
completionBlock:completionBlock];
87+
RCTImageLoaderCancellationBlock cancelationBlock = loaderRequest.cancellationBlock;
88+
sharedCancelationFunction.assign([cancelationBlock]() { cancelationBlock(); });
89+
90+
auto result = dispatch_group_wait(imageWaitGroup, dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC));
91+
if (result != 0) {
92+
RCTLogError(@"Getting an image timed out");
93+
}
94+
return imageRequest;
95+
}
96+
97+
@end

0 commit comments

Comments
 (0)