OSX ELCapitan,XCode8.2,Objective-c可可项目。
在我的一个NSobject类中,一个方法需要一个CIContext才能将CIImage位图数据呈现到内存中(CIContext渲染至Bitmap)。这种方法被频繁调用,因此速度是一个重要因素。由于为每个渲染创建一个CIContext非常耗时,因此我尝试创建一个CIContext属性,在类init中进行init,然后在方法中将其作为self.context调用。
但是,如果以这种方式进行操作,则会在CIContext的呈现命令中收到一条BADEXECESS错误消息。 如果我将声明和初始化放在方法中,并每次创建一个CIContext,则在调用此方法时,一切正常。 如果我在其他任何地方声明它,则会导致错误。
@interface myClass:NSObject
@property CIContext *ciContext;
@end
@implementation myClass
-(instancetype)init {
self = [super init];
_ciContext = [CIContext context];
//self.ciContext = [CIContext context]; same result
return self;
}
-(void)myMethod {
[_ciContext render:xxx toBitmap:xxx rowBytes:xxx bounds:xxx format:xxx colorSpace:xxx];
//[self.ciContext render:xxx toBitmap:xxx rowBytes:xxx bounds:xxx format:xxx colorSpace:xxx]; same result
}
导致BADEXCESS。以下内容也不起作用:
@interface myClass:NSObject
@end
@implementation myClass {
CIContext *ciContext;
}
-(instancetype)init {
self = [super init];
ciContext = [CIContext context];
return self;
}
-(void)myMethod {
[ciContext render:xxx toBitmap:xxx rowBytes:xxx bounds:xxx format:xxx colorSpace:xxx];
}
但是:
@interface myClass:NSObject
@end
@implementation myClass
-(void)myMethod {
CIContext *ciContext = [CIContext context];
[ciContext render:xxx toBitmap:xxx rowBytes:xxx bounds:xxx format:xxx colorSpace:xxx];
}
完美运行。
???
我该如何解决?如何创建班级的可重用CIContext?还是真的,我每次调用要使用的方法时都必须创建一个新的?
答案 0 :(得分:0)
OS X El Capitan,Xcode 8.2
我没有OS X El Capitan。以下代码已在启用了ARC的macOS Catalina&Xcode 11.5上进行了测试(自OS X Lion IIRC以来,您也应该能够使用ARC,受到完全支持)。
@property ciContext *CIContext
,...)。myClass
作为类名,它实际上应该是MyClass
。
CIContext
和CIImage
对象是不可变的,因此多个线程可以使用相同的CIContext
对象来呈现CIImage
对象。但是,CIFilter
对象是可变的,因此不能在线程之间安全地共享。每个线程必须创建自己的CIFilter
对象,但是您可以在线程之间传递过滤器的不变的输入和输出CIImage
对象。
因此,CIContext
和CIImage
可以在多个线程中使用,而没有任何问题。
计算 100 张图像的平均颜色。
ImageProcessing.h
:
@import CoreImage;
@import AppKit;
@interface ImageProcessing : NSObject
+ (nonnull instancetype)sharedInstance;
- (nullable NSColor *)averageColorOf:(nonnull CIImage *)image;
@end
ImageProcessing.m
:
#import "ImageProcessing.h"
@interface ImageProcessing ()
@property (nonnull, nonatomic, strong) CIContext *context;
@end
@implementation ImageProcessing
+ (instancetype)sharedInstance {
static ImageProcessing *instance = nil;
static dispatch_once_t token;
dispatch_once(&token, ^{
instance = [[self alloc] init];
});
return instance;
}
- (instancetype)init {
if ((self = [super init]) == nil) {
return nil;
}
_context = [CIContext context];
return self;
}
- (NSColor *)averageColorOf:(CIImage *)image {
CIVector *extent = [[CIVector alloc] initWithX:image.extent.origin.x
Y:image.extent.origin.y
Z:image.extent.size.width
W:image.extent.size.height];
CIFilter *filter = [CIFilter filterWithName:@"CIAreaAverage"
keysAndValues:kCIInputImageKey, image, kCIInputExtentKey, extent, nil];
CIImage *output = [filter outputImage];
if (output == nil) {
return nil;
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
if (colorSpace == NULL) {
return nil;
}
char bitmap[4] = {0};
[_context render:output
toBitmap:&bitmap
rowBytes:4 bounds:CGRectMake(0, 0, 1, 1)
format:kCIFormatRGBA8
colorSpace:colorSpace];
CGColorSpaceRelease(colorSpace);
return [NSColor colorWithSRGBRed:(CGFloat)bitmap[0] / 255.0
green:(CGFloat)bitmap[1] / 255.0
blue:(CGFloat)bitmap[2] / 255.0
alpha:(CGFloat)bitmap[3] / 255.0];
}
@end
AppDelegate.m
:
将其放置在任何地方,我只是使用了应用程序委托,因为我已经打开了另一个示例项目。
#import "AppDelegate.h"
#import "ImageProcessing.h"
#import "pthread.h"
@interface AppDelegate ()
@property (nonatomic, strong) NSOperationQueue *queue;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_queue = [[NSOperationQueue alloc] init];
_queue.maxConcurrentOperationCount = 10;
_queue.qualityOfService = NSQualityOfServiceUtility;
// Be aware that this is an image from bundle, not from Assets
NSURL *url = [[NSBundle mainBundle] URLForResource:@"image" withExtension:@"png"];
CIImage *image = [CIImage imageWithContentsOfURL:url];
for (NSUInteger i = 0 ; i < 100 ; i++) {
[_queue addOperationWithBlock:^{
mach_port_t threadID = pthread_mach_thread_np(pthread_self());
NSColor *color = [[ImageProcessing sharedInstance] averageColorOf:image];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *output = [NSString stringWithFormat:@"%4lu - %08x - %@", (unsigned long)i, threadID, color];
NSLog(@"%@", output);
});
}];
}
}
@end
输出:
...
84 - 00003f03 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
89 - 0000d217 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
98 - 0001470b - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
99 - 00007b07 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
97 - 0000d313 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
94 - 00003a07 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
91 - 00001907 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
95 - 00014f13 - sRGB IEC61966-2.1 colorspace -0.501961 -0.180392 -0.45098 -0.00392157
...