Create a gist now

Instantly share code, notes, and snippets.

@jwilling /LBHView.h
Last active Jun 30, 2016

A terrible, terrible hack to toggle AppKit's destruction of layer modifications.
#import <Cocoa/Cocoa.h>
@interface LBHView : NSView
/// This property controls whether the view can indirectly control its
/// backing layer's properties, specifically the following:
/// `affineTransform`
/// `anchorPoint`
///
/// These properties cannot be modified on the layer during the time that
/// this property is enabled.
///
/// This is useful for preventing NSView from resetting custom modifications
/// to the layer, such as transforms for custom animations.
@property (nonatomic, assign) BOOL ignoreNSViewBackingLayerSynchronization;
@end
#import "LBHView.h"
#import "JRSwizzle.h"
#import <objc/runtime.h>
@interface CALayer (LBHBackingLayerHacks)
@property (nonatomic, assign) BOOL lbh_ignoreNSViewBackingLayerSynchronization;
@end
static void *LBHBackingLayerSynchronizationAssociatedObjectKey = &LBHBackingLayerSynchronizationAssociatedObjectKey;
@implementation CALayer (LBHBackingLayerHacks)
- (void)setLbh_ignoreNSViewBackingLayerSynchronization:(BOOL)ignores {
objc_setAssociatedObject(self, LBHBackingLayerSynchronizationAssociatedObjectKey, @(ignores), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)lbh_ignoreNSViewBackingLayerSynchronization {
return [objc_getAssociatedObject(self, LBHBackingLayerSynchronizationAssociatedObjectKey) boolValue];
}
- (void)lbh_setAffineTransform:(CGAffineTransform)m {
if (self.lbh_ignoreNSViewBackingLayerSynchronization) {
// do nothing
} else {
[self lbh_setAffineTransform:m];
}
}
- (void)lbh_setAnchorPoint:(CGPoint)anchorPoint {
if (self.lbh_ignoreNSViewBackingLayerSynchronization) {
// do nothing
} else {
[self lbh_setAnchorPoint:anchorPoint];
}
}
@end
@implementation LBHView
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self == nil) return nil;
self.wantsLayer = YES;
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
return self;
}
- (CALayer *)makeBackingLayer {
CALayer *backingLayer = [super makeBackingLayer];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Get the class for _NSBackingLayer.
Class nsBackingLayerClass = backingLayer.class;
NSError *error = nil;
// Swizzle the setters for anchor point and affine transform.
[nsBackingLayerClass jr_swizzleMethod:@selector(setAnchorPoint:) withMethod:@selector(lbh_setAnchorPoint:) error:&error];
[nsBackingLayerClass jr_swizzleMethod:@selector(setAffineTransform:) withMethod:@selector(lbh_setAffineTransform:) error:&error];
if (error != nil) {
NSLog(@"Fatal error: could not swizzle the view's backing layer! %@", error);
}
});
return backingLayer;
}
- (void)setIgnoreNSViewBackingLayerSynchronization:(BOOL)ignoreSynchronization {
self.layer.lbh_ignoreNSViewBackingLayerSynchronization = ignoreSynchronization;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment