Роб прав, что renderInContext:
является правильным методом для использования здесь.Визуализация в контексте действительно визуализирует пиксельные данные слоя в контекст.Вот пример приложения, которое будет рисовать 10 000 слоев в фоновом потоке ...
Приложение выполняет следующие действия:
- Создает UIView
- Добавляет 10 000 слоев кслой этого вида
- Рендеринг начинается при касании экрана (т. е. это пример приложения iOS)
- Создает фоновый поток
- Отображает слой UIView в контекст (который вturn рендерит свои подслои)
- Создает UIImage с содержимым контекста рендеринга
- Добавляет новое изображение на экран в UIImageView
- Он делает все это во время выполнениятаймер в основном потоке, показывающий, что фоновый поток фактически не блокирует основной поток
Вот код ...
Сначала создайтеподпредставление с большим количеством слоев:
@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);
}
В-третьих, создайте цикл рендерингас методом обратного вызова, который ставитn изображение на экране после завершения рендеринга.
-(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
[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];
});
});
}
ПРИМЕЧАНИЕ: если все ваши слои не находятся в одном и том же подслое, вы можете легко вызвать цикл for
, который переводит контекст в и изисточник каждого CALayer и нарисовать каждый слой отдельно в сам контекст
Когда я запускаю это, я получаю следующий вывод:
2013-03-18 07:14:28.617 C4iOS[21086:907] render was called
2013-03-18 07:14:28.648 C4iOS[21086:907] 1 (main thread running)
2013-03-18 07:14:28.680 C4iOS[21086:907] 2 (main thread running)
2013-03-18 07:14:28.709 C4iOS[21086:907] 3 (main thread running)
2013-03-18 07:14:28.737 C4iOS[21086:907] 4 (main thread running)
2013-03-18 07:14:28.767 C4iOS[21086:907] 5 (main thread running)
2013-03-18 07:14:28.798 C4iOS[21086:907] 6 (main thread running)
2013-03-18 07:14:28.828 C4iOS[21086:907] 7 (main thread running)
2013-03-18 07:14:28.859 C4iOS[21086:907] 8 (main thread running)
2013-03-18 07:14:28.887 C4iOS[21086:907] 9 (main thread running)
2013-03-18 07:14:28.917 C4iOS[21086:907] 10 (main thread running)
2013-03-18 07:14:28.948 C4iOS[21086:907] 11 (main thread running)
2013-03-18 07:14:28.978 C4iOS[21086:907] 12 (main thread running)
2013-03-18 07:14:29.010 C4iOS[21086:907] 13 (main thread running)
2013-03-18 07:14:29.037 C4iOS[21086:907] 14 (main thread running)
2013-03-18 07:14:29.069 C4iOS[21086:907] 15 (main thread running)
2013-03-18 07:14:29.097 C4iOS[21086:907] 16 (main thread running)
2013-03-18 07:14:29.130 C4iOS[21086:907] 17 (main thread running)
2013-03-18 07:14:29.159 C4iOS[21086:907] 18 (main thread running)
2013-03-18 07:14:29.189 C4iOS[21086:907] 19 (main thread running)
2013-03-18 07:14:29.217 C4iOS[21086:907] 20 (main thread running)
2013-03-18 07:14:29.248 C4iOS[21086:907] 21 (main thread running)
2013-03-18 07:14:29.280 C4iOS[21086:907] 22 (main thread running)
2013-03-18 07:14:29.309 C4iOS[21086:907] 23 (main thread running)
2013-03-18 07:14:29.337 C4iOS[21086:907] 24 (main thread running)
2013-03-18 07:14:29.369 C4iOS[21086:907] 25 (main thread running)
2013-03-18 07:14:29.397 C4iOS[21086:907] 26 (main thread running)
2013-03-18 07:14:29.405 C4iOS[21086:907] rendering complete