Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 7 additions & 16 deletions MSCachedAsyncViewDrawing.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef void (^MSCachedAsyncViewDrawingCompletionBlock)(UIImage *drawnImage);
* Once finished, it'll call the completion block on the main thread with the drawn UIImage object.
* `MSCachedAsyncViewDrawing` objects keep an internal cache so multiple calls to this method with the same `cacheKey`
* will result in the immediate call of `completionBlock`.
* @param `synchronous` Passing YES will run synchronously and will call completionBlock before returning nil
* @param `cacheKey` make sure you create a string with the paremeters of the view. Two views configured
* differently (say, different text or font color) should have different cache keys to avoid collisions)
* @param backgroundColor if you want a transparent image, just pass [UIColor clearColor].
Expand All @@ -33,21 +34,11 @@ typedef void (^MSCachedAsyncViewDrawingCompletionBlock)(UIImage *drawnImage);
* @return NSOperation associated with the drawing. If you're enqueuing a lot of drawing, you may want to cancel the operation
* before it finishes if the result is not needed anymore to save resources.
*/
- (NSOperation *)drawViewAsyncWithCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock
completionBlock:(MSCachedAsyncViewDrawingCompletionBlock)completionBlock;

/**
* @discussion this is the synchronous version of the other method.
* It waits until the image is loaded and returns it instead of calling a completion block.
* @param `drawBlock` is called on the caller thread.
*/
- (UIImage *)drawViewSyncWithCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock;

- (NSOperation *)drawViewSynchronous:(BOOL)synchronous
withCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock
completionBlock:(MSCachedAsyncViewDrawingCompletionBlock)completionBlock;

@end
93 changes: 31 additions & 62 deletions MSCachedAsyncViewDrawing.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ + (_MSViewDrawingOperation *)viewDrawingBlockOperationWithBlock:(void (^)(_MSVie

@end

typedef void (^MSCachedAsyncViewDrawingOperationBlock)(_MSViewDrawingOperation *operation);

@implementation _MSViewDrawingOperation

+ (_MSViewDrawingOperation *)viewDrawingBlockOperationWithBlock:(void (^)(_MSViewDrawingOperation *))block
+ (_MSViewDrawingOperation *)viewDrawingBlockOperationWithBlock:(MSCachedAsyncViewDrawingOperationBlock)operationBlock
{
_MSViewDrawingOperation *operation = [[self alloc] init];

__weak _MSViewDrawingOperation *weakOperation = operation;

[operation addExecutionBlock:^{
block(weakOperation);
operationBlock(weakOperation);
}];

return operation;
Expand Down Expand Up @@ -80,12 +82,12 @@ - (id)init

#pragma mark - Private

- (NSOperation *)drawViewWithCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock
completionBlock:(MSCachedAsyncViewDrawingCompletionBlock)completionBlock
waitUntilDone:(BOOL)waitUntilDone
- (NSOperation *)drawViewSynchronous:(BOOL)synchronous
withCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock
completionBlock:(MSCachedAsyncViewDrawingCompletionBlock)completionBlock;
{
UIImage *cachedImage = [self.cache objectForKey:cacheKey];

Expand All @@ -98,28 +100,28 @@ - (NSOperation *)drawViewWithCacheKey:(NSString *)cacheKey
MSCachedAsyncViewDrawingDrawBlock heapDrawBlock = [drawBlock copy];
MSCachedAsyncViewDrawingCompletionBlock heapCompletionBlock = [completionBlock copy];

_MSViewDrawingOperation *operation = [_MSViewDrawingOperation viewDrawingBlockOperationWithBlock:[^(_MSViewDrawingOperation *operation) {
MSCachedAsyncViewDrawingOperationBlock operationBlock = ^(_MSViewDrawingOperation *operation) {
if (operation.isCancelled)
{
return;
}

BOOL opaque = [self colorIsOpaque:backgroundColor];

UIGraphicsBeginImageContextWithOptions(imageSize, opaque, 0);

if (operation.isCancelled)
{
UIGraphicsEndImageContext();
return;
}

CGContextRef context = UIGraphicsGetCurrentContext();

CGRect rectToDraw = (CGRect){.origin = CGPointZero, .size = imageSize};

BOOL shouldDrawBackgroundColor = ![backgroundColor isEqual:[UIColor clearColor]];

if (shouldDrawBackgroundColor)
{
CGContextSaveGState(context);
Expand All @@ -129,29 +131,31 @@ - (NSOperation *)drawViewWithCacheKey:(NSString *)cacheKey
}
CGContextRestoreGState(context);
}

heapDrawBlock(rectToDraw);

if (operation.isCancelled)
{
UIGraphicsEndImageContext();
return;
}

UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

if (operation.isCancelled)
{
UIGraphicsEndImageContext();
return;
}

[self.cache setObject:resultImage forKey:cacheKey];

operation.resultImage = resultImage;
} copy]];
};

_MSViewDrawingOperation *operation = [_MSViewDrawingOperation viewDrawingBlockOperationWithBlock:[operationBlock copy]];

__strong __block _MSViewDrawingOperation *_operation = operation;

Expand All @@ -162,54 +166,19 @@ - (NSOperation *)drawViewWithCacheKey:(NSString *)cacheKey
});
};

[self.operationQueue addOperation:operation];

if (waitUntilDone)
if (synchronous)
{
[operation waitUntilFinished];
operationBlock(operation);
completionBlock(operation.resultImage);
return nil;
}
else
{
[self.operationQueue addOperation:operation];
return operation;
}
}

#pragma mark - Public

- (NSOperation *)drawViewAsyncWithCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock
completionBlock:(MSCachedAsyncViewDrawingCompletionBlock)completionBlock
{
return [self drawViewWithCacheKey:cacheKey
size:imageSize
backgroundColor:backgroundColor
drawBlock:drawBlock
completionBlock:completionBlock
waitUntilDone:NO];
}

- (UIImage *)drawViewSyncWithCacheKey:(NSString *)cacheKey
size:(CGSize)imageSize
backgroundColor:(UIColor *)backgroundColor
drawBlock:(MSCachedAsyncViewDrawingDrawBlock)drawBlock
{
__block UIImage *image = nil;

[self drawViewWithCacheKey:cacheKey
size:imageSize
backgroundColor:backgroundColor
drawBlock:drawBlock
completionBlock:^(UIImage *drawnImage) {
image = drawnImage;
}
waitUntilDone:YES];

return image;
}

#pragma mark - Aux

- (BOOL)colorIsOpaque:(UIColor *)color
Expand Down