Skip to content

Instantly share code, notes, and snippets.

@C4Code
Created March 18, 2013 13:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save C4Code/5187147 to your computer and use it in GitHub Desktop.
Save C4Code/5187147 to your computer and use it in GitHub Desktop.
Rendering thousands of layers into a cgcontext on a background thread...
//
// C4WorkSpace.m
//
// Created by Travis Kirton
//
#import "C4WorkSpace.h"
@implementation C4WorkSpace {
UIView *v;
dispatch_queue_t backgroundRenderQueue;
CFTimeInterval beginTime;
NSTimer *timer;
NSInteger timerCallCount;
}
-(void)setup {
//create a view to hold a bunch of CALayers
v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
v.center = CGPointMake(384,512);
//create a buch of CALayers and add them to a view
for(int i = 0; i < 10000; i++) {
CALayer *l = [[CALayer alloc] init];
l.frame = CGRectMake([self random:390],[self random:390],10,10);
l.backgroundColor = [UIColor blueColor].CGColor;
l.borderColor = [UIColor orangeColor].CGColor;
l.borderWidth = 2.0f;
[v.layer addSublayer:l];
}
//add the view to the application's main view
[self.view addSubview:v];
}
-(NSInteger)random:(NSInteger)value {
srandomdev();
return ((NSInteger)random())%value;
}
-(void)touchesBegan {
timer = [NSTimer scheduledTimerWithTimeInterval:0.03f target:self selector:@selector(printTime) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[self render];
}
-(void)printTime {
NSLog(@"%d (main thread running)",++timerCallCount);
}
-(void)render {
NSLog(@"render was called");
//create the queue
backgroundRenderQueue = dispatch_queue_create("backgroundRenderQueue",DISPATCH_QUEUE_CONCURRENT);
//create a async call on the background queue
dispatch_async(backgroundRenderQueue, ^{
//create a cgcontext
NSUInteger width = (NSUInteger)v.frame.size.width;
NSUInteger height = (NSUInteger)v.frame.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
unsigned char *rawData = malloc(height * bytesPerRow);
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
//render the layer and its subviews
//NOTE: if your layers aren't all in the same sublayer
//you can easily call a for(..;..;..) that translates the context to and from the origin of each CALayer
//and draw each layer individually into the context itself
[v.layer renderInContext:context];
//create a callback async on the main queue when rendering is complete
dispatch_async(dispatch_get_main_queue(), ^{
//create an image from the context
UIImage *m = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
UIImageView *uiiv = [[UIImageView alloc] initWithImage:m];
//add the image view to the main view
[self.view addSubview:uiiv];
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
NSLog(@"rendering complete");
[timer invalidate];
});
});
}
@end
@stripes
Copy link

stripes commented Aug 5, 2017

You create a new background queue each time you call render? Why not keep just one? Or use the system concurrent queue?

Why call srandomdev for each random number? Why not once in unit?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment