Skip to content

Commit

Permalink
Introduced very basic cache system to the web snapshots.
Browse files Browse the repository at this point in the history
This cache returns a raw UIView which is not copied at all, so if there are multiple views which refers the cache it would be broken. We need to fix this by returning "copied view" or UIImage snapshot instead.
  • Loading branch information
akisute committed Dec 14, 2013
1 parent 4ab60e5 commit d675178
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 11 deletions.
56 changes: 45 additions & 11 deletions TwitterClient/TwitterMediaCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ + (TwitterWebRenderRequestItem *)infoWithRenderRequest:(TwitterWebRenderRequest
@interface TwitterMediaCache ()
@property (nonatomic) NSURLSession *mediaSession;
@property (nonatomic) TwitterWebRenderWorker *webRenderWorker;
@property (nonatomic) NSMutableArray *webRenderRequestQueue; // must be locked before read/write
@property (nonatomic) NSMutableArray *webRenderRequestQueue; // V=TwitterWebRenderRequestItem. Must be locked before read/write.
@property (nonatomic) NSCache *webSnapshotCache; // V=UIView, K=TwitterWebRenderRequest.
@end

@implementation TwitterMediaCache
Expand Down Expand Up @@ -66,10 +67,14 @@ - (id)init
// Setup web render worker and queue
self.webRenderWorker = [[TwitterWebRenderWorker alloc] init];
self.webRenderRequestQueue = [NSMutableArray array];
self.webSnapshotCache = [[NSCache alloc] init];
self.webSnapshotCache.totalCostLimit = 20*1000*1000;
}
return self;
}

#pragma mark - Public

- (BOOL)imageWithURL:(NSURL *)url completionHandler:(TwitterMediaCacheImageCompletionHandler)completionHandler
{
TwitterMediaCacheImageCompletionHandler callback = [completionHandler copy];
Expand Down Expand Up @@ -99,15 +104,21 @@ - (BOOL)snapshotViewWithRenderRequest:(TwitterWebRenderRequest *)renderRequest c
3. Dequeue URL requests into render workers whenever they are available
4. When URL requests are finished in render workers, call resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets: to grab the snapshot, then return it
For current implementation, only 1 render worker is available at a time. Having multiple render workers could result in very complecated code.
For current implementation, only 1 render worker is available at a time.
For current implementation, only portrait mode is available. The UIWebView doesn't handle view rotation itself without any support of UIViewControllers, so we need some solutions to this
*/

// TODO: need a cache system

[self __enqueueSnapshotViewRenderRequest:renderRequest completionHandler:completionHandler];
[self __popSnapshotViewRenderRequest:NO];
UIView *cachedView = [self __cachedSnapshotViewForRenderRequest:renderRequest];
if (cachedView) {
TwitterMediaCacheSnapshotViewCompletionHandler callback = [completionHandler copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
callback(cachedView);
});
} else {
[self __enqueueSnapshotViewRenderRequest:renderRequest completionHandler:completionHandler];
[self __popSnapshotViewRenderRequest:NO];
}
return YES;
}

Expand All @@ -132,6 +143,8 @@ - (void)cancelSnapshotViewRequestWithRequestID:(NSString *)requestID
}
}

#pragma mark - Private

- (void)__enqueueSnapshotViewRenderRequest:(TwitterWebRenderRequest *)renderRequest completionHandler:(TwitterMediaCacheSnapshotViewCompletionHandler)completionHandler
{
NSLog(@"enqueueing render request: %@", renderRequest.url);
Expand Down Expand Up @@ -161,13 +174,34 @@ - (void)__popSnapshotViewRenderRequest:(BOOL)force
}

NSLog(@"consuming render request: %@", item.renderRequest.url);
[self.webRenderWorker startRenderingWithRenderRequest:item.renderRequest completionHandler:^(UIView *view, NSURL *url) {
NSLog(@"render request completed: %@", url);
item.callback(view);
UIView *cachedView = [self __cachedSnapshotViewForRenderRequest:item.renderRequest];
if (cachedView) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self __popSnapshotViewRenderRequest:YES];
item.callback(cachedView);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self __popSnapshotViewRenderRequest:YES];
});
});
}];
} else {
[self.webRenderWorker startRenderingWithRenderRequest:item.renderRequest completionHandler:^(UIView *view, NSURL *url) {
NSLog(@"render request completed: %@", url);
[self __storeSnapshotView:view forRenderRequest:item.renderRequest];
item.callback(view);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self __popSnapshotViewRenderRequest:YES];
});
}];
}
}

- (void)__storeSnapshotView:(UIView *)view forRenderRequest:(TwitterWebRenderRequest *)renderRequest
{
[self.webSnapshotCache setObject:view forKey:renderRequest cost:(view.bounds.size.width * view.bounds.size.height * 8)];
}

- (UIView *)__cachedSnapshotViewForRenderRequest:(TwitterWebRenderRequest *)renderRequest
{
return [self.webSnapshotCache objectForKey:renderRequest];
}

@end
14 changes: 14 additions & 0 deletions TwitterClient/TwitterWebRenderRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,18 @@ + (TwitterWebRenderRequest *)renderRequestWithURL:(NSURL *)url mode:(TwitterWebR
return renderRequest;
}

- (NSUInteger)hash
{
return [self.url hash] + self.mode;
}

- (BOOL)isEqual:(id)object
{
if ([object isKindOfClass:[TwitterWebRenderRequest class]]) {
TwitterWebRenderRequest *request = object;
return [self.url isEqual:request.url] && self.mode == request.mode;
}
return NO;
}

@end

0 comments on commit d675178

Please sign in to comment.