Je dois peindre une image en utilisant certaines données et la montrer sur mon application iphone. Comme la peinture prend beaucoup de temps (2-3 secondes sur l'appareil), je veux peindre sur un fil différent. Aussi, je veux pouvoir annuler la peinture, changer quelque chose dans les données et recommencer. Il est donc préférable pour moi d'utiliser NSOperation. Maintenant, quand je dessine sur le fil principal, tout va bien.
Lorsque je fais exactement la même chose avec la sous-classe NSOperation, tout semble correct, mais seulement 95% du temps. Parfois, il ne dessine pas l'image complète. Parfois, il ne dessine pas de texte. Parfois, il utilise des couleurs différentes, il pourrait y avoir des points rouges/vert/bleu dispersés sur l'image, etc etc etcProblèmes lors de l'utilisation de Quartz 2D sur NSOperation
J'ai fait un exemple très courte pour illustrer ceci: D'abord, nous faisons tout le tableau sur un thread principal dans une méthode régulière:
//setting up bitmap context
size_t width = 400;
size_t height = 400;
size_t bitsPerComponent = 8;
size_t bytesPerRow = 4 * width;
void* imageData = malloc(bytesPerRow * height);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(imageData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
CFRelease(colorSpace);
//transforming it to usual coordinate system
CGRect mapRect = CGRectMake(0, 0, width, height);
UIGraphicsPushContext(context);
CGContextTranslateCTM(context, 0, mapRect.size.height);
CGContextScaleCTM(context, 1, -1);
//actull drawing - nothing complicated here, 2 lines and 3 text strings on white background
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, mapRect);
CGContextSetLineWidth(context, 3);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 10, 10);
CGContextAddLineToPoint(context, 20, 20);
CGContextStrokePath(context);
CGContextMoveToPoint(context, 20, 20);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
[UIColor blackColor].set;
[[NSString stringWithString:@"tag1"] drawInRect:CGRectMake(10, 10, 40, 15) withFont:[UIFont systemFontOfSize:15]];
[[NSString stringWithString:@"tag2"] drawInRect:CGRectMake(20, 20, 40, 15) withFont:[UIFont systemFontOfSize:15]];
[[NSString stringWithString:@"tag3"] drawInRect:CGRectMake(100, 100, 40, 15) withFont:[UIFont systemFontOfSize:15]];
//getting UIImage from bitmap context
CGImageRef _trueMap = CGBitmapContextCreateImage(context);
if (_trueMap) {
UIImage* _map = [UIImage imageWithCGImage:_trueMap];
CFRelease(_trueMap);
//displaying what we got
//self.map leads to UIImageView
self.map = _map;
}
//releasing context and memmory
UIGraphicsPopContext();
CFRelease(context);
free(imageData);
Pas d'erreur ici. Fonctionne toujours
Maintenant, je vais sous-classe NSOperation et copier-coller là ce code: Interface:
@interface Painter : NSOperation {
//The controller which contains UIImageView we will use to display image
MapViewController* mapViewController;
CGContextRef context;
void* imageData;
}
@property (nonatomic, assign) MapViewController* mapViewController;
- (id) initWithRootController:(MapViewController*)mvc__;
@end
Maintenant, les méthodes:
- (id) initWithRootController:(MapViewController*)mvc__ {
if (self = [super init]) {
self.mapViewController = mvc__;
size_t width = 400;
size_t height = 400;
size_t bitsPerComponent = 8;
size_t bytesPerRow = 4 * width;
imageData = malloc(bytesPerRow * height);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(imageData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
CFRelease(colorSpace);
}
return self;
}
- (void) main {
size_t width = 400;
size_t height = 400;
//transforming it to usual coordinate system
CGRect mapRect = CGRectMake(0, 0, width, height);
UIGraphicsPushContext(context);
CGContextTranslateCTM(context, 0, mapRect.size.height);
CGContextScaleCTM(context, 1, -1);
//actull drawing - nothing complicated here, 2 lines and 3 text strings on white background
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, mapRect);
CGContextSetLineWidth(context, 3);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 10, 10);
CGContextAddLineToPoint(context, 20, 20);
CGContextStrokePath(context);
CGContextMoveToPoint(context, 20, 20);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
[UIColor blackColor].set;
[[NSString stringWithString:@"tag1"] drawInRect:CGRectMake(10, 10, 40, 15) withFont:[UIFont systemFontOfSize:15]];
[[NSString stringWithString:@"tag2"] drawInRect:CGRectMake(20, 20, 40, 15) withFont:[UIFont systemFontOfSize:15]];
[[NSString stringWithString:@"tag3"] drawInRect:CGRectMake(100, 100, 40, 15) withFont:[UIFont systemFontOfSize:15]];
//getting UIImage from bitmap context
CGImageRef _trueMap = CGBitmapContextCreateImage(context);
if (_trueMap) {
UIImage* _map = [UIImage imageWithCGImage:_trueMap];
CFRelease(_trueMap);
//displaying what we got
[mapViewController performSelectorOnMainThread:@selector(setMap:) withObject:_map waitUntilDone:YES];
}
//releasing context and memmory
UIGraphicsPopContext();
CFRelease(context);
free(imageData);
}
Encore une fois, aucun changement de code significatif entre ce 2 morceaux de code. Et quand je commence cette opération comme ceci:
NSOperationQueue* repaintQueue = [[NSOperationQueue alloc] init];
repaintQueue.maxConcurrentOperationCount = 1;
[repaintQueue addOperation:[[[Painter alloc] initWithRootController:self] autorelease]];
Cela fonctionnera. Mais pas toujours, parfois l'image contiendra des artefacts.
J'ai aussi fait quelques captures d'écran pour illustrer la question, mais n'a pas pu les poster = ( Quoi qu'il en soit, il y a une capture d'écran qui montre la ligne rouge et 3 lignes de texte (ce qui est bien) et une capture d'écran qui montre la ligne rouge, pas de lignes de texte et "tag2" écrit à l'envers sur le contrôleur de la barre d'onglets
Alors, quel est le problème? Je ne peux pas utiliser Quartz avec NSOperation? Y at-il une sorte de restriction sur le dessin sur des fils séparés? il y a un moyen de contourner ces restrictions si c'est le cas Si quelqu'un a déjà vu ce problème, veuillez répondre à:
Cette explication semble très plausible, cependant, je ne peux toujours pas le faire fonctionner. Je l'ai fait appeler drawInRect: WithFont: sur le thread principal, mais cela n'a pas aidé.J'ai remplacé ceci: [[NSString stringWithString: @ "tag1"] drawInRect: CGRectMake (10, 10, 40, 15) avecFont: [UIFont systemFontOfSize: 15]]; Avec ceci: [self performSelectorOnMainThread: @selector (drawText :) withObject: @ "tag1" waitUntilDone: OUI]; , où drawText: est - (void) drawText: (NSString *) text__ {[texte__ drawInRect: CGRectMake (20, 20, 40, 15) withFont: [UIFont systemFontOfSize: 15]]; } D'autres conseils s'il vous plaît? – Alexey
J'ai oublié de mentionner que j'ai également déplacé imageWithCGImage: sur le fil principal. – Alexey
Ok, je l'ai eu le travail après avoir remplacé tous les appels UIKit avec des appels CG. Toujours aucune idée de comment le faire fonctionner avec n'importe quel appel UIKit. – Alexey