Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 6784cc2

Browse files
maickigarrettmoon
authored andcommitted
Add assertion against externally setting .image in specific ASImageNode subclasses
1 parent 54eba88 commit 6784cc2

8 files changed

Lines changed: 75 additions & 16 deletions

File tree

AsyncDisplayKit.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@
204204
6907C2591DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 6907C2571DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m */; };
205205
6907C25A1DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 6907C2571DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m */; };
206206
69127CFE1DD2B387004BF6E2 /* ASEventLog.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 696F01EA1DD2AF450049FBD5 /* ASEventLog.h */; };
207+
69309D461DF3B1B50089FA48 /* ASImageNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 69309D451DF3B1B50089FA48 /* ASImageNode+Private.h */; };
207208
693117CE1DC7C72700DE4784 /* ASDisplayNode+Deprecated.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 683489271D70DE3400327501 /* ASDisplayNode+Deprecated.h */; };
208209
69527B121DC84292004785FB /* ASLayoutElementStylePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 69527B111DC84292004785FB /* ASLayoutElementStylePrivate.h */; };
209210
6959433E1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */; };
@@ -1002,6 +1003,7 @@
10021003
68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASVisibilityProtocols.m; sourceTree = "<group>"; };
10031004
6907C2561DC4ECFE00374C66 /* ASObjectDescriptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASObjectDescriptionHelpers.h; sourceTree = "<group>"; };
10041005
6907C2571DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASObjectDescriptionHelpers.m; sourceTree = "<group>"; };
1006+
69309D451DF3B1B50089FA48 /* ASImageNode+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASImageNode+Private.h"; sourceTree = "<group>"; };
10051007
69527B111DC84292004785FB /* ASLayoutElementStylePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutElementStylePrivate.h; path = AsyncDisplayKit/Layout/ASLayoutElementStylePrivate.h; sourceTree = SOURCE_ROOT; };
10061008
6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayout.mm; sourceTree = "<group>"; };
10071009
6959433D1D70815300B0EE1F /* ASDisplayNodeLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeLayout.h; sourceTree = "<group>"; };
@@ -1609,6 +1611,7 @@
16091611
68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */,
16101612
058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */,
16111613
058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */,
1614+
69309D451DF3B1B50089FA48 /* ASImageNode+Private.h */,
16121615
ACF6ED431B17847A00DA7C62 /* ASInternalHelpers.h */,
16131616
ACF6ED441B17847A00DA7C62 /* ASInternalHelpers.m */,
16141617
69C4CAF51DA3147000B1EC9B /* ASLayoutElementStylePrivate.h */,
@@ -1857,6 +1860,7 @@
18571860
34EFC7631B701CBF00AD841F /* ASCenterLayoutSpec.h in Headers */,
18581861
9C70F20C1CDBE9B6007D6C76 /* ASCollectionDataController.h in Headers */,
18591862
18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */,
1863+
69309D461DF3B1B50089FA48 /* ASImageNode+Private.h in Headers */,
18601864
9C8898BD1C738BB800D6B02E /* ASTextKitFontSizeAdjuster.h in Headers */,
18611865
B35061F51B010EFD0018CF92 /* ASCollectionView.h in Headers */,
18621866
ACE87A2C1D73696800D7FF06 /* ASSectionContext.h in Headers */,

AsyncDisplayKit/ASImageNode.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
199199
#pragma mark - Setter / Getter
200200

201201
- (void)setImage:(UIImage *)image
202+
{
203+
[self __setImage:image];
204+
}
205+
206+
- (void)__setImage:(UIImage *)image
202207
{
203208
ASDN::MutexLocker l(__instanceLock__);
204209
if (!ASObjectIsEqual(_image, image)) {

AsyncDisplayKit/ASMultiplexImageNode.mm

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@
1111
#if TARGET_OS_IOS
1212

1313
#import "ASMultiplexImageNode.h"
14+
#import "ASImageNode+Private.h"
1415
#import <AssetsLibrary/AssetsLibrary.h>
1516

1617
#import "ASAvailability.h"
1718
#import "ASDisplayNode+Subclasses.h"
1819
#import "ASDisplayNode+FrameworkPrivate.h"
20+
#import "ASDisplayNodeExtras.h"
1921
#import "ASLog.h"
2022
#import "ASPhotosFrameworkImageRequest.h"
2123
#import "ASEqualityHelpers.h"
2224
#import "ASInternalHelpers.h"
23-
#import "ASDisplayNodeExtras.h"
2425

2526
#if !AS_IOS8_SDK_OR_LATER
2627
#error ASMultiplexImageNode can be used on iOS 7, but must be linked against the iOS 8 SDK.
@@ -233,7 +234,7 @@ - (void)didExitPreloadState
233234

234235
// setting this to nil makes the node fetch images the next time its display starts
235236
_loadedImageIdentifier = nil;
236-
self.image = nil;
237+
[self __setImage:nil];
237238
}
238239

239240
- (void)didEnterPreloadState
@@ -325,6 +326,12 @@ - (void)didExitVisibleState
325326

326327
#pragma mark - Core
327328

329+
- (void)setImage:(UIImage *)image
330+
{
331+
ASDisplayNodeAssert(NO, @"Setting the image directly to an ASMultiplexImageNode is not allowed.");
332+
[self __setImage:image];
333+
}
334+
328335
- (void)setDelegate:(id <ASMultiplexImageNodeDelegate>)delegate
329336
{
330337
if (_delegate == delegate)
@@ -520,7 +527,7 @@ - (void)_updateProgressImageBlockOnDownloaderIfNeeded
520527
if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
521528
return;
522529
}
523-
strongSelf.image = progressImage;
530+
[self __setImage:progressImage];
524531
};
525532
}
526533
[_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier];
@@ -538,7 +545,7 @@ - (void)_clearImage
538545
if (shouldReleaseImageOnBackgroundThread) {
539546
ASPerformBackgroundDeallocation(image);
540547
}
541-
self.image = nil;
548+
[self __setImage:nil];
542549
}
543550

544551
#pragma mark -
@@ -867,7 +874,7 @@ - (void)_finishedLoadingImage:(UIImage *)image forIdentifier:(id)imageIdentifier
867874
UIImage *previousImage = self.image;
868875

869876
self.loadedImageIdentifier = imageIdentifier;
870-
self.image = image;
877+
[self __setImage:image];
871878

872879
if (_delegateFlags.updatedImage) {
873880
[_delegate multiplexImageNode:self didUpdateImage:image withIdentifier:imageIdentifier fromImage:previousImage withIdentifier:previousIdentifier];

AsyncDisplayKit/ASNetworkImageNode.mm

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
//
1010

1111
#import "ASNetworkImageNode.h"
12+
#import "ASImageNode+Private.h"
1213

1314
#import "ASBasicImageDownloader.h"
1415
#import "ASDisplayNodeInternal.h"
16+
#import "ASDisplayNodeExtras.h"
1517
#import "ASDisplayNode+Subclasses.h"
1618
#import "ASDisplayNode+FrameworkPrivate.h"
1719
#import "ASEqualityHelpers.h"
1820
#import "ASInternalHelpers.h"
1921
#import "ASImageContainerProtocolCategories.h"
20-
#import "ASDisplayNodeExtras.h"
2122

2223
#if PIN_REMOTE_IMAGE
2324
#import "ASPINRemoteImageDownloader.h"
@@ -67,6 +68,7 @@ @interface ASNetworkImageNode ()
6768
unsigned int cacheSupportsSynchronousFetch:1;
6869
} _cacheFlags;
6970
}
71+
7072
@end
7173

7274
@implementation ASNetworkImageNode
@@ -116,6 +118,12 @@ - (void)dealloc
116118

117119
#pragma mark - Public methods -- must lock
118120

121+
- (void)setImage:(UIImage *)image
122+
{
123+
ASDisplayNodeAssert(NO, @"Setting the image directly to an ASNetworkImageNode is not allowed. Please either use the defaultImage property or move to an ASImageNode");
124+
[self __setImage:image];
125+
}
126+
119127
- (void)setURL:(NSURL *)URL
120128
{
121129
[self setURL:URL resetToDefault:YES];
@@ -136,7 +144,7 @@ - (void)setURL:(NSURL *)URL resetToDefault:(BOOL)reset
136144

137145
BOOL hasURL = _URL == nil;
138146
if (reset || hasURL) {
139-
self.image = _defaultImage;
147+
[self __setImage:_defaultImage];
140148
/* We want to maintain the order that currentImageQuality is set regardless of the calling thread,
141149
so always use a dispatch_async to ensure that we queue the operations in the correct order.
142150
(see comment in displayDidFinish) */
@@ -171,7 +179,7 @@ - (void)setDefaultImage:(UIImage *)defaultImage
171179
dispatch_async(dispatch_get_main_queue(), ^{
172180
self.currentImageQuality = hasURL ? 0.0 : 1.0;
173181
});
174-
self.image = defaultImage;
182+
[self __setImage:defaultImage];
175183
}
176184
}
177185

@@ -256,7 +264,7 @@ - (void)displayWillStartAsynchronously:(BOOL)asynchronously
256264
if (_imageLoaded == NO && _URL && _downloadIdentifier == nil) {
257265
UIImage *result = [[_cache synchronouslyFetchedCachedImageWithURL:_URL] asdk_image];
258266
if (result) {
259-
self.image = result;
267+
[self __setImage:result];
260268
_imageLoaded = YES;
261269
dispatch_async(dispatch_get_main_queue(), ^{
262270
_currentImageQuality = 1.0;
@@ -340,7 +348,7 @@ - (void)handleProgressImage:(UIImage *)progressImage progress:(CGFloat)progress
340348
if (ASObjectIsEqual(_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) {
341349
return;
342350
}
343-
self.image = progressImage;
351+
[self __setImage:progressImage];
344352
dispatch_async(dispatch_get_main_queue(), ^{
345353
// See comment in -displayDidFinish for why this must be dispatched to main
346354
self.currentImageQuality = progress;
@@ -396,7 +404,7 @@ - (void)_clearImage
396404
ASPerformBackgroundDeallocation(image);
397405
}
398406
self.animatedImage = nil;
399-
self.image = _defaultImage;
407+
[self __setImage:_defaultImage];
400408
_imageLoaded = NO;
401409
// See comment in -displayDidFinish for why this must be dispatched to main
402410
dispatch_async(dispatch_get_main_queue(), ^{
@@ -456,7 +464,7 @@ - (void)_lazilyLoadImageIfNecessary
456464

457465
dispatch_async(dispatch_get_main_queue(), ^{
458466
if (self.shouldCacheImage) {
459-
self.image = [UIImage imageNamed:_URL.path.lastPathComponent];
467+
[self __setImage:[UIImage imageNamed:_URL.path.lastPathComponent]];
460468
} else {
461469
// First try to load the path directly, for efficiency assuming a developer who
462470
// doesn't want caching is trying to be as minimal as possible.
@@ -486,7 +494,7 @@ - (void)_lazilyLoadImageIfNecessary
486494
if (animatedImage != nil) {
487495
self.animatedImage = animatedImage;
488496
} else {
489-
self.image = nonAnimatedImage;
497+
[self __setImage:nonAnimatedImage];
490498
}
491499
}
492500

@@ -522,7 +530,7 @@ - (void)_lazilyLoadImageIfNecessary
522530
if ([imageContainer asdk_animatedImageData] && _downloaderFlags.downloaderImplementsAnimatedImage) {
523531
strongSelf.animatedImage = [_downloader animatedImageWithData:[imageContainer asdk_animatedImageData]];
524532
} else {
525-
strongSelf.image = [imageContainer asdk_image];
533+
[strongSelf __setImage:[imageContainer asdk_image]];
526534
}
527535
dispatch_async(dispatch_get_main_queue(), ^{
528536
strongSelf->_currentImageQuality = 1.0;

AsyncDisplayKit/ASVideoNode.mm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#import "ASEqualityHelpers.h"
1717
#import "ASInternalHelpers.h"
1818
#import "ASDisplayNodeExtras.h"
19+
#import "ASImageNode+Private.h"
1920

2021
static BOOL ASAssetIsEqual(AVAsset *asset1, AVAsset *asset2) {
2122
return ASObjectIsEqual(asset1, asset2)
@@ -300,7 +301,7 @@ - (void)setVideoPlaceholderImage:(UIImage *)image
300301
if (image != nil) {
301302
self.contentMode = ASContentModeFromVideoGravity(_gravity);
302303
}
303-
self.image = image;
304+
[self __setImage:image];
304305
}
305306

306307
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// ASImageNode+Private.h
3+
// AsyncDisplayKit
4+
//
5+
// Created by Michael Schneider on 12/3/16.
6+
// Copyright © 2016 Facebook. All rights reserved.
7+
//
8+
9+
#pragma mark - ASImageNode
10+
11+
#import "ASImageNode.h"
12+
13+
@interface ASImageNode (Private)
14+
15+
/*
16+
* Set the image property of the ASImageNode. Subclasses like ASNetworkImageNode do not allow setting the
17+
* image property directly and throw an assertion. There still needs to be a way for subclasses of
18+
* ASNetworkImageNode to set the image.
19+
*/
20+
- (void)__setImage:(UIImage *)image;
21+
22+
@end

AsyncDisplayKitTests/ASMultiplexImageNodeTests.m

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,10 @@ - (void)testUncachedDownload
302302
[mockDelegate verify];
303303
}
304304

305-
@end
305+
- (void)testThatSettingAnImageExternallyWillThrow
306+
{
307+
ASMultiplexImageNode *multiplexImageNode = [[ASMultiplexImageNode alloc] init];
308+
XCTAssertThrows(multiplexImageNode.image = [UIImage imageNamed:@""]);
309+
}
310+
311+
@end

AsyncDisplayKitTests/ASNetworkImageNodeTests.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ - (void)testThatProgressBlockIsSetAndClearedCorrectlyOnChangeURL
7171
[downloader verifyWithDelay:5];
7272
}
7373

74+
- (void)testThatSettingAnImageExternallyWillThrow
75+
{
76+
ASNetworkImageNode *networkImageNode = [[ASNetworkImageNode alloc] init];
77+
XCTAssertThrows(networkImageNode.image = [UIImage imageNamed:@""]);
78+
}
79+
7480
@end
7581

7682
@implementation ASTestImageCache

0 commit comments

Comments
 (0)