Skip to content

Commit b47d109

Browse files
Empty bounds image view fallback to thumbnail size (#15815)
2 parents 775755b + ec85502 commit b47d109

File tree

5 files changed

+52
-1
lines changed

5 files changed

+52
-1
lines changed

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- [internal] Reduced fields fetched for variations in Point of Sale [https://github.com/woocommerce/woocommerce-ios/pull/15712]
1313
- [*] Order List: Prevent last updated time being truncated at larger font sizes [https://github.com/woocommerce/woocommerce-ios/pull/15717]
1414
- [***] Creating shipping labels is now supported for stores with the WooCommerce Shipping extension [https://github.com/woocommerce/woocommerce-ios/pull/15738]
15+
- [internal] Optimized image handling with a fallback thumbnail size for image views that have empty bounds, preventing high memory usage. [https://github.com/woocommerce/woocommerce-ios/pull/15815]
1516

1617
22.5
1718
-----

WooCommerce/Classes/Tools/ImageService/DefaultImageService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct DefaultImageService: ImageService {
5959
let targetSize: CGSize
6060
if ServiceLocator.featureFlagService.isFeatureFlagEnabled(
6161
.productImageOptimizedHandling
62-
) {
62+
) && !imageView.bounds.isEmpty {
6363
let scale = UIScreen.main.scale
6464
targetSize = CGSize(
6565
width: imageView.bounds.width * scale,

WooCommerce/Classes/ViewRelated/Products/Cells/ProductsTabProductTableViewCell.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ extension ProductsTabProductTableViewCell {
101101
productImageView.layer.borderWidth = 0
102102
} else {
103103
configureProductImageViewForBigImages()
104+
/// Make sure `productImageView` is laid out and gained bounds
105+
productImageView.layoutIfNeeded()
106+
104107
productImageView.image = .productsTabProductCellPlaceholderImage
105108
if let productURLString = viewModel.imageUrl {
106109
imageService.downloadAndCacheImageForImageView(productImageView,

WooCommerce/WooCommerceTests/Mocks/MockKingfisherImageDownloader.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ final class MockKingfisherImageDownloader: Kingfisher.ImageDownloader {
55
// Mocks in-memory cache.
66
private let imagesByKey: [String: UIImage]
77

8+
private(set) var capturedProcessor: ImageProcessor?
9+
810
init(imagesByKey: [String: UIImage]) {
911
self.imagesByKey = imagesByKey
1012
super.init(name: "Mock!")
@@ -14,6 +16,14 @@ final class MockKingfisherImageDownloader: Kingfisher.ImageDownloader {
1416
options: KingfisherOptionsInfo? = nil,
1517
progressBlock: DownloadProgressBlock?,
1618
completionHandler: ((Result<ImageLoadingResult, KingfisherError>) -> Void)? = nil) -> DownloadTask? {
19+
if let options = options {
20+
for option in options {
21+
if case .processor(let processor) = option {
22+
capturedProcessor = processor
23+
break
24+
}
25+
}
26+
}
1727
if let image = imagesByKey[url.absoluteString] {
1828
completionHandler?(.success(.init(image: image, url: url, originalData: Data())))
1929
} else {
@@ -25,6 +35,7 @@ final class MockKingfisherImageDownloader: Kingfisher.ImageDownloader {
2535
override func downloadImage(with url: URL,
2636
options: KingfisherParsedOptionsInfo,
2737
completionHandler: ((Result<ImageLoadingResult, KingfisherError>) -> Void)? = nil) -> DownloadTask? {
38+
capturedProcessor = options.processor
2839
if let image = imagesByKey[url.absoluteString] {
2940
completionHandler?(.success(.init(image: image, url: url, originalData: Data())))
3041
} else {

WooCommerce/WooCommerceTests/Tools/DefaultImageServiceTests.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,40 @@ final class DefaultImageServiceTests: XCTestCase {
265265

266266
waitForExpectations(timeout: Constants.expectationTimeout, handler: nil)
267267
}
268+
269+
func testDownloadAndCacheImageForImageView_withEmptyBounds_usesDefaultThumbnailSize() {
270+
// Given
271+
let originalFeatureFlagService = ServiceLocator.featureFlagService
272+
defer {
273+
ServiceLocator.setFeatureFlagService(originalFeatureFlagService)
274+
}
275+
276+
ServiceLocator.setFeatureFlagService(
277+
MockFeatureFlagService(
278+
isProductImageOptimizedHandlingEnabled: true
279+
)
280+
)
281+
282+
let mockImageView = UIImageView(frame: .zero)
283+
let mockCache = MockImageCache(name: "Testing")
284+
let mockDownloader = MockKingfisherImageDownloader(imagesByKey: [url.absoluteString: testImage])
285+
imageService = DefaultImageService(imageCache: mockCache, imageDownloader: mockDownloader)
286+
287+
// When
288+
imageService.downloadAndCacheImageForImageView(
289+
mockImageView,
290+
with: url.absoluteString,
291+
placeholder: nil,
292+
progressBlock: nil,
293+
completion: nil
294+
)
295+
296+
// Then
297+
guard let downsamplingProcessor = mockDownloader.capturedProcessor as? DownsamplingImageProcessor else {
298+
XCTFail("DownsamplingImageProcessor not found or not the correct type")
299+
return
300+
}
301+
302+
XCTAssertEqual(downsamplingProcessor.size, CGSize(width: 800, height: 800))
303+
}
268304
}

0 commit comments

Comments
 (0)