Skip to content

Instantly share code, notes, and snippets.

@xhruso00
Last active October 16, 2019 19:33
Show Gist options
  • Save xhruso00/7eedfd1158d4678ed3fc49d9a0ecc060 to your computer and use it in GitHub Desktop.
Save xhruso00/7eedfd1158d4678ed3fc49d9a0ecc060 to your computer and use it in GitHub Desktop.
Magic behind CIFilter modernization (for swift) on macOS 10.15 uses class_addMethod
#import <Cocoa/Cocoa.h>
#import <CoreImage/CoreImage.h>
@protocol CILineOverlay <CIFilter>
@property (nonatomic, retain) CIImage *inputImage;
@property (nonatomic) float threshold;
@end
@interface CIFilter(CILineOverlay)
+ (CIFilter<CILineOverlay>*) lineOverlayFilter;
@property (nonatomic, retain) CIImage *inputImage;
@property (nonatomic) float threshold; //notice that they dropped input keyword
@end
#import <CoreImage/CoreImage.h>
#include <objc/runtime.h>
@implementation CIFilter(CILineOverlay)
@dynamic inputImage;
@dynamic threshold;
+ (CIFilter<CILineOverlay>*) lineOverlayFilter
{
CIFilter<CILineOverlay>*filter = (CIFilter<CILineOverlay>*)[CIFilter filterWithName:@"CILineOverlay"];
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
class_addMethod([self class], @selector(threshold), (IMP)floatGetter, "f@:"); //dynamically add input keyword
class_addMethod([self class], @selector(setThreshold:), (IMP)floatSetter, "v@:f");
});
return filter;
}
static float floatGetter(id self, SEL _cmd) {
NSString *selector = NSStringFromSelector(_cmd);
NSString *firstLetter = [[selector substringWithRange:NSMakeRange(0, 1)] uppercaseString];
NSString *key = [@"input" stringByAppendingString:[selector stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstLetter]];
/// SEL == threshold
/// key == inputThreshold
id value = [self valueForKey:key];
float number = NAN;
if (value && [value isKindOfClass:[NSNumber class]]) {
number = [value floatValue];
}
return number;
}
static void floatSetter(id self, SEL _cmd, float value) {
NSString *selector = NSStringFromSelector(_cmd);
NSString *key = [selector stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@"input"];
/// SEL == setThreshold
/// key == inputThreshold
[self setValue:@(value) forKey:[key substringWithRange:NSMakeRange(0, [key length] - 1)]];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment