* swizzle-with-block

* Fix UILabel

* Returning IMP from method_getImplementation and add UILabelVC

* Remove NSObject+DarkModeKit
This commit is contained in:
Levin Li 2020-06-10 09:52:34 +08:00 коммит произвёл GitHub
Родитель 8e52a4812d
Коммит facaafc73d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 196 добавлений и 173 удалений

Просмотреть файл

@ -7,8 +7,6 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
8C071AEC23683BF5001AB7B2 /* NSObject+DarkModeKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C071AEA23683BF5001AB7B2 /* NSObject+DarkModeKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
8C071AED23683BF5001AB7B2 /* NSObject+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C071AEB23683BF5001AB7B2 /* NSObject+DarkModeKit.m */; };
8C1915D82361EFDB004A606A /* FluentDarkModeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C1915CE2361EFDB004A606A /* FluentDarkModeKit.framework */; }; 8C1915D82361EFDB004A606A /* FluentDarkModeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C1915CE2361EFDB004A606A /* FluentDarkModeKit.framework */; };
8C1915DD2361EFDB004A606A /* DarkModeKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C1915DC2361EFDB004A606A /* DarkModeKitTests.swift */; }; 8C1915DD2361EFDB004A606A /* DarkModeKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C1915DC2361EFDB004A606A /* DarkModeKitTests.swift */; };
8C63F64323A36B2700D93CF4 /* UIButtonVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C63F64123A36B0900D93CF4 /* UIButtonVC.swift */; }; 8C63F64323A36B2700D93CF4 /* UIButtonVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C63F64123A36B0900D93CF4 /* UIButtonVC.swift */; };
@ -56,6 +54,7 @@
8CDA62A52366DAA9004895B5 /* DMDynamicColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8CDA62A52366DAA9004895B5 /* DMDynamicColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */; settings = {ATTRIBUTES = (Public, ); }; };
8CE066CF239E5582002CE16D /* UIColor+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */; }; 8CE066CF239E5582002CE16D /* UIColor+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */; };
8CE066D0239E5586002CE16D /* UIImage+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D8722398E7A30043276A /* UIImage+DarkModeKit.m */; }; 8CE066D0239E5586002CE16D /* UIImage+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D8722398E7A30043276A /* UIImage+DarkModeKit.m */; };
EA7316F1248F5055009AE037 /* UILabelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7316EF248F5050009AE037 /* UILabelVC.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -97,8 +96,6 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
8C071AEA23683BF5001AB7B2 /* NSObject+DarkModeKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+DarkModeKit.h"; sourceTree = "<group>"; };
8C071AEB23683BF5001AB7B2 /* NSObject+DarkModeKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+DarkModeKit.m"; sourceTree = "<group>"; };
8C1915CE2361EFDB004A606A /* FluentDarkModeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FluentDarkModeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8C1915CE2361EFDB004A606A /* FluentDarkModeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FluentDarkModeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8C1915D22361EFDB004A606A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 8C1915D22361EFDB004A606A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8C1915D72361EFDB004A606A /* FluentDarkModeKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FluentDarkModeKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8C1915D72361EFDB004A606A /* FluentDarkModeKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FluentDarkModeKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@ -151,6 +148,7 @@
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DMDynamicImage.m; sourceTree = "<group>"; }; 8CDA62892366DAA9004895B5 /* DMDynamicImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DMDynamicImage.m; sourceTree = "<group>"; };
8CDA628A2366DAA9004895B5 /* DarkModeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarkModeManager.swift; sourceTree = "<group>"; }; 8CDA628A2366DAA9004895B5 /* DarkModeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarkModeManager.swift; sourceTree = "<group>"; };
8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DMDynamicColor.h; sourceTree = "<group>"; }; 8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DMDynamicColor.h; sourceTree = "<group>"; };
EA7316EF248F5050009AE037 /* UILabelVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILabelVC.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -216,8 +214,6 @@
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */, 8CDA62892366DAA9004895B5 /* DMDynamicImage.m */,
8CDA62712366DAA9004895B5 /* DMTraitCollection.h */, 8CDA62712366DAA9004895B5 /* DMTraitCollection.h */,
8CDA62722366DAA9004895B5 /* DMTraitCollection.m */, 8CDA62722366DAA9004895B5 /* DMTraitCollection.m */,
8C071AEA23683BF5001AB7B2 /* NSObject+DarkModeKit.h */,
8C071AEB23683BF5001AB7B2 /* NSObject+DarkModeKit.m */,
8CC8D86F2398E7520043276A /* DMNamespace.h */, 8CC8D86F2398E7520043276A /* DMNamespace.h */,
8CC8D86B2398E4EC0043276A /* UIColor+DarkModeKit.h */, 8CC8D86B2398E4EC0043276A /* UIColor+DarkModeKit.h */,
8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */, 8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */,
@ -291,6 +287,7 @@
8C7B250A23A22A70002E2558 /* UIActivityIndicatorViewVC.swift */, 8C7B250A23A22A70002E2558 /* UIActivityIndicatorViewVC.swift */,
8C63F64123A36B0900D93CF4 /* UIButtonVC.swift */, 8C63F64123A36B0900D93CF4 /* UIButtonVC.swift */,
8C63F64423A374CF00D93CF4 /* UIPageControlVC.swift */, 8C63F64423A374CF00D93CF4 /* UIPageControlVC.swift */,
EA7316EF248F5050009AE037 /* UILabelVC.swift */,
8CAFD9DD23715FAB001A63B8 /* Assets.xcassets */, 8CAFD9DD23715FAB001A63B8 /* Assets.xcassets */,
8CAFD9DF23715FAB001A63B8 /* LaunchScreen.storyboard */, 8CAFD9DF23715FAB001A63B8 /* LaunchScreen.storyboard */,
8CAFD9E223715FAB001A63B8 /* Info.plist */, 8CAFD9E223715FAB001A63B8 /* Info.plist */,
@ -338,7 +335,6 @@
files = ( files = (
8CC8D86D2398E4EC0043276A /* UIColor+DarkModeKit.h in Headers */, 8CC8D86D2398E4EC0043276A /* UIColor+DarkModeKit.h in Headers */,
8CC8D8702398E7520043276A /* DMNamespace.h in Headers */, 8CC8D8702398E7520043276A /* DMNamespace.h in Headers */,
8C071AEC23683BF5001AB7B2 /* NSObject+DarkModeKit.h in Headers */,
8CDA628D2366DAA9004895B5 /* DMTraitCollection.h in Headers */, 8CDA628D2366DAA9004895B5 /* DMTraitCollection.h in Headers */,
8CDA628C2366DAA9004895B5 /* FluentDarkModeKit.h in Headers */, 8CDA628C2366DAA9004895B5 /* FluentDarkModeKit.h in Headers */,
8CB63E41238551F3008ABCE2 /* UIView+DarkModeKit.h in Headers */, 8CB63E41238551F3008ABCE2 /* UIView+DarkModeKit.h in Headers */,
@ -551,7 +547,6 @@
8CDA629C2366DAA9004895B5 /* UINavigationBar+DarkModeKit.swift in Sources */, 8CDA629C2366DAA9004895B5 /* UINavigationBar+DarkModeKit.swift in Sources */,
8CDA629D2366DAA9004895B5 /* UITabBar+DarkModeKit.swift in Sources */, 8CDA629D2366DAA9004895B5 /* UITabBar+DarkModeKit.swift in Sources */,
8CDA62922366DAA9004895B5 /* UIToolbar+DarkModeKit.swift in Sources */, 8CDA62922366DAA9004895B5 /* UIToolbar+DarkModeKit.swift in Sources */,
8C071AED23683BF5001AB7B2 /* NSObject+DarkModeKit.m in Sources */,
8CDA629A2366DAA9004895B5 /* UIPageControl+DarkModeKit.swift in Sources */, 8CDA629A2366DAA9004895B5 /* UIPageControl+DarkModeKit.swift in Sources */,
8CDA62932366DAA9004895B5 /* UIButton+DarkModeKit.swift in Sources */, 8CDA62932366DAA9004895B5 /* UIButton+DarkModeKit.swift in Sources */,
8CDA629B2366DAA9004895B5 /* UITableView+DarkModeKit.swift in Sources */, 8CDA629B2366DAA9004895B5 /* UITableView+DarkModeKit.swift in Sources */,
@ -582,6 +577,7 @@
8C7B250C23A22A80002E2558 /* UIActivityIndicatorViewVC.swift in Sources */, 8C7B250C23A22A80002E2558 /* UIActivityIndicatorViewVC.swift in Sources */,
8CAFD9D923715FAA001A63B8 /* ViewController.swift in Sources */, 8CAFD9D923715FAA001A63B8 /* ViewController.swift in Sources */,
8C63F64323A36B2700D93CF4 /* UIButtonVC.swift in Sources */, 8C63F64323A36B2700D93CF4 /* UIButtonVC.swift in Sources */,
EA7316F1248F5055009AE037 /* UILabelVC.swift in Sources */,
8CAFD9ED2371606D001A63B8 /* NavigationController.swift in Sources */, 8CAFD9ED2371606D001A63B8 /* NavigationController.swift in Sources */,
8CAFD9D523715FAA001A63B8 /* AppDelegate.swift in Sources */, 8CAFD9D523715FAA001A63B8 /* AppDelegate.swift in Sources */,
8C63F64623A374D300D93CF4 /* UIPageControlVC.swift in Sources */, 8C63F64623A374D300D93CF4 /* UIPageControlVC.swift in Sources */,

Просмотреть файл

@ -5,7 +5,6 @@
#import "DMDynamicImage.h" #import "DMDynamicImage.h"
#import "DMTraitCollection.h" #import "DMTraitCollection.h"
#import "NSObject+DarkModeKit.h"
@import ObjectiveC; @import ObjectiveC;

Просмотреть файл

@ -6,7 +6,6 @@
#import <FluentDarkModeKit/DMDynamicColor.h> #import <FluentDarkModeKit/DMDynamicColor.h>
#import <FluentDarkModeKit/DMDynamicImage.h> #import <FluentDarkModeKit/DMDynamicImage.h>
#import <FluentDarkModeKit/DMTraitCollection.h> #import <FluentDarkModeKit/DMTraitCollection.h>
#import <FluentDarkModeKit/NSObject+DarkModeKit.h>
#import <FluentDarkModeKit/UIColor+DarkModeKit.h> #import <FluentDarkModeKit/UIColor+DarkModeKit.h>
#import <FluentDarkModeKit/UIImage+DarkModeKit.h> #import <FluentDarkModeKit/UIImage+DarkModeKit.h>
#import <FluentDarkModeKit/UIView+DarkModeKit.h> #import <FluentDarkModeKit/UIView+DarkModeKit.h>

Просмотреть файл

@ -1,19 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (DarkModeKit)
/// Swizzle two instance methods for class that calls this method.
///
/// Return NO if any selector cannot find corresponding method.
+ (BOOL)dm_swizzleInstanceMethod:(SEL)fromSelector to:(SEL)toSelector;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -1,29 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import "NSObject+DarkModeKit.h"
@import ObjectiveC;
@implementation NSObject (DarkModeKit)
+ (BOOL)dm_swizzleInstanceMethod:(SEL)selector1 to:(SEL)selector2 {
Method method1 = class_getInstanceMethod(self, selector1);
Method method2 = class_getInstanceMethod(self, selector2);
if (!method1 || !method2) {
return NO;
}
if (class_addMethod(self, selector1, method_getImplementation(method2), method_getTypeEncoding(method2))) {
class_replaceMethod(self, selector2, method_getImplementation(method1), method_getTypeEncoding(method1));
} else {
method_exchangeImplementations(method1, method2);
}
return YES;
}
@end

Просмотреть файл

@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface UIImage (DarkModeKit) @interface UIImage (DarkModeKit)
+ (void)dm_swizzleIsEqual;
+ (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage + (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage
NS_SWIFT_UNAVAILABLE("Use init(_:light:dark:) instead."); NS_SWIFT_UNAVAILABLE("Use init(_:light:dark:) instead.");

Просмотреть файл

@ -5,14 +5,34 @@
#import "UIImage+DarkModeKit.h" #import "UIImage+DarkModeKit.h"
#import "DMDynamicImage.h" #import "DMDynamicImage.h"
#import "NSObject+DarkModeKit.h"
@import ObjectiveC; @import ObjectiveC;
@implementation UIImage (DarkModeKit) @implementation UIImage (DarkModeKit)
+ (void)load { + (void)dm_swizzleIsEqual {
[UIImage dm_swizzleInstanceMethod:@selector(isEqual:) to:@selector(dm_isEqual:)]; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(isEqual:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIImage isEqual:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^BOOL(UIImage *self, UIImage *other) {
/// On iOS 13, UIImage `isEqual:` somehow changes internally and doesn't work for `NSProxy`,
/// here we forward the message to internal images manually
UIImage *realSelf = self;
UIImage *realOther = other;
if (object_getClass(self) == DMDynamicImageProxy.class) {
realSelf = ((DMDynamicImageProxy *)self).resolvedImage;
}
if (object_getClass(other) == DMDynamicImageProxy.class) {
realOther = ((DMDynamicImageProxy *)other).resolvedImage;
}
return ((BOOL(*)(UIImage *, SEL, UIImage *))imp)(realSelf, selector, realOther);
}), method_getTypeEncoding(method));
});
} }
+ (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage { + (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage {
@ -25,18 +45,4 @@
return [UIImage dm_imageWithLightImage:lightImage darkImage:darkImage]; return [UIImage dm_imageWithLightImage:lightImage darkImage:darkImage];
} }
- (BOOL)dm_isEqual:(UIImage *)other {
/// On iOS 13, UIImage `isEqual:` somehow changes internally and doesn't work for `NSProxy`,
/// here we forward the message to internal images manually
UIImage *realSelf = self;
UIImage *realOther = other;
if (object_getClass(self) == DMDynamicImageProxy.class) {
realSelf = ((DMDynamicImageProxy *)self).resolvedImage;
}
if (object_getClass(other) == DMDynamicImageProxy.class) {
realOther = ((DMDynamicImageProxy *)other).resolvedImage;
}
return [realSelf dm_isEqual:realOther];
}
@end @end

Просмотреть файл

@ -10,24 +10,24 @@
@implementation UIView (DarkModeKit) @implementation UIView (DarkModeKit)
static void (*dm_original_setBackgroundColor)(UIView *, SEL, UIColor *);
static void dm_setBackgroundColor(UIView *self, SEL _cmd, UIColor *color) {
if ([color isKindOfClass:[DMDynamicColor class]]) {
self.dm_dynamicBackgroundColor = (DMDynamicColor *)color;
} else {
self.dm_dynamicBackgroundColor = nil;
}
dm_original_setBackgroundColor(self, _cmd, color);
}
// https://stackoverflow.com/questions/42677534/swizzling-on-properties-that-conform-to-ui-appearance-selector
+ (void)dm_swizzleSetBackgroundColor { + (void)dm_swizzleSetBackgroundColor {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
Method method = class_getInstanceMethod(self, @selector(setBackgroundColor:)); SEL selector = @selector(setBackgroundColor:);
dm_original_setBackgroundColor = (void *)method_getImplementation(method); Method method = class_getInstanceMethod(self, selector);
method_setImplementation(method, (IMP)dm_setBackgroundColor); if (!method)
NSAssert(NO, @"Method not found for [UIView setBackgroundColor:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^(UIView *self, UIColor *backgroundColor) {
if ([backgroundColor isKindOfClass:[DMDynamicColor class]]) {
self.dm_dynamicBackgroundColor = (DMDynamicColor *)backgroundColor;
}
else {
self.dm_dynamicBackgroundColor = nil;
}
((void (*)(UIView *, SEL, UIColor *))imp)(self, selector, backgroundColor);
}), method_getTypeEncoding(method));
}); });
} }

Просмотреть файл

@ -6,7 +6,6 @@
#import "../DMDynamicImage.h" #import "../DMDynamicImage.h"
#import "../DMNamespace.h" #import "../DMNamespace.h"
#import "../DMTraitCollection.h" #import "../DMTraitCollection.h"
#import "../NSObject+DarkModeKit.h"
#import "../UIColor+DarkModeKit.h" #import "../UIColor+DarkModeKit.h"
#import "../UIImage+DarkModeKit.h" #import "../UIImage+DarkModeKit.h"
#import "../UIView+DarkModeKit.h" #import "../UIView+DarkModeKit.h"

Просмотреть файл

@ -18,6 +18,7 @@ public final class DarkModeManager: NSObject {
UILabel.swizzleDidMoveToWindowOnce UILabel.swizzleDidMoveToWindowOnce
// Images // Images
UIImage.dm_swizzleIsEqual()
UIImageView.swizzleSetImageOnce UIImageView.swizzleSetImageOnce
UIImageView.swizzleInitImageOnce UIImageView.swizzleInitImageOnce
UITabBarItem.swizzleSetImageOnce UITabBarItem.swizzleSetImageOnce

Просмотреть файл

@ -15,23 +15,41 @@ extension UIImageView {
} }
static let swizzleSetImageOnce: Void = { static let swizzleSetImageOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(setter: image), to: #selector(dm_setImage(_:))) { let selector = #selector(setter: image)
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: #selector(setter: image))) guard let method = class_getInstanceMethod(UIImageView.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: selector))
return
} }
let imp = method_getImplementation(method)
class_replaceMethod(UIImageView.self, selector, imp_implementationWithBlock({ (self: UIImageView, image: UIImage?) -> Void in
if object_getClass(image) == DMDynamicImageProxy.self {
self.dm_dynamicImage = image
}
else {
self.dm_dynamicImage = nil
}
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIImageView, Selector, UIImage?) -> Void).self)
oldIMP(self, selector, image)
} as @convention(block) (UIImageView, UIImage?) -> Void), method_getTypeEncoding(method))
}() }()
static let swizzleInitImageOnce: Void = { static let swizzleInitImageOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(UIImageView.init(image:)), to: #selector(UIImageView.dm_init(image:))) { let selector = #selector(UIImageView.init(image:))
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: #selector(setter: image))) guard let method = class_getInstanceMethod(UIImageView.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: selector))
return
} }
}()
@objc dynamic func dm_init(image: UIImage?) -> UIImageView { let imp = method_getImplementation(method)
if object_getClass(image) == DMDynamicImageProxy.self { class_replaceMethod(UIImageView.self, selector, imp_implementationWithBlock({ (self: UIImageView, image: UIImage?) -> UIImageView in
dm_dynamicImage = image if object_getClass(image) == DMDynamicImageProxy.self {
} self.dm_dynamicImage = image
return dm_init(image: image) }
} let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIImageView, Selector, UIImage?) -> UIImageView).self)
return oldIMP(self, selector, image)
} as @convention(block) (UIImageView, UIImage?) -> UIImageView), method_getTypeEncoding(method))
}()
override func dm_updateDynamicImages() { override func dm_updateDynamicImages() {
super.dm_updateDynamicImages() super.dm_updateDynamicImages()
@ -40,14 +58,4 @@ extension UIImageView {
image = dynamicImage image = dynamicImage
} }
} }
@objc dynamic func dm_setImage(_ image: UIImage?) {
if object_getClass(image) == DMDynamicImageProxy.self {
dm_dynamicImage = image
}
else {
dm_dynamicImage = nil
}
dm_setImage(image)
}
} }

Просмотреть файл

@ -9,9 +9,21 @@ extension UILabel {
} }
static let swizzleDidMoveToWindowOnce: Void = { static let swizzleDidMoveToWindowOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(didMoveToWindow), to: #selector(dm_didMoveToWindow)) { let selector = #selector(didMoveToWindow)
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UILabel.self, selector: #selector(didMoveToWindow))) guard let method = class_getInstanceMethod(UILabel.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UILabel.self, selector: selector))
return
} }
let imp = method_getImplementation(method)
class_replaceMethod(UILabel.self, selector, imp_implementationWithBlock({ (self: UILabel) -> Void in
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UILabel, Selector) -> Void).self)
oldIMP(self, selector)
if self.currentUserInterfaceStyle != DMTraitCollection.current.userInterfaceStyle {
self.currentUserInterfaceStyle = DMTraitCollection.current.userInterfaceStyle
self.dmTraitCollectionDidChange(nil)
}
} as @convention(block) (UILabel) -> Void), method_getTypeEncoding(method))
}() }()
private var currentUserInterfaceStyle: DMUserInterfaceStyle? { private var currentUserInterfaceStyle: DMUserInterfaceStyle? {
@ -19,16 +31,14 @@ extension UILabel {
set { objc_setAssociatedObject(self, &Constants.currentThemeKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } set { objc_setAssociatedObject(self, &Constants.currentThemeKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
} }
@objc private dynamic func dm_didMoveToWindow() {
dm_didMoveToWindow()
if currentUserInterfaceStyle != DMTraitCollection.current.userInterfaceStyle {
currentUserInterfaceStyle = DMTraitCollection.current.userInterfaceStyle
dmTraitCollectionDidChange(nil)
}
}
override open func dmTraitCollectionDidChange(_ previousTraitCollection: DMTraitCollection?) { override open func dmTraitCollectionDidChange(_ previousTraitCollection: DMTraitCollection?) {
super.dmTraitCollectionDidChange(previousTraitCollection) super.dmTraitCollectionDidChange(previousTraitCollection)
guard #available(iOS 12.0, *) else {
// Fix for iOS 11.x
updateDynamicColorInAttributedText()
return
}
} }
private func updateDynamicColorInAttributedText() { private func updateDynamicColorInAttributedText() {

Просмотреть файл

@ -33,15 +33,43 @@ extension UITabBarItem: DMTraitEnvironment {
} }
static let swizzleSetImageOnce: Void = { static let swizzleSetImageOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(setter: image), to: #selector(dm_setImage(_:))) { let selector = #selector(setter: image)
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: #selector(setter: image))) guard let method = class_getInstanceMethod(UITabBarItem.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: selector))
return
} }
let imp = method_getImplementation(method)
class_replaceMethod(UITabBarItem.self, selector, imp_implementationWithBlock({ (self: UITabBarItem, image: UIImage?) -> Void in
if object_getClass(image) == DMDynamicImageProxy.self {
self.dm_dynamicImage = image
}
else {
self.dm_dynamicImage = nil
}
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UITabBarItem, Selector, UIImage?) -> Void).self)
oldIMP(self, selector, image)
} as @convention(block) (UITabBarItem, UIImage?) -> Void), method_getTypeEncoding(method))
}() }()
static let swizzleSetSelectedImageOnce: Void = { static let swizzleSetSelectedImageOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(setter: selectedImage), to: #selector(dm_setSelectedImage(_:))) { let selector = #selector(setter: selectedImage)
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: #selector(setter: selectedImage))) guard let method = class_getInstanceMethod(UITabBarItem.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: selector))
return
} }
let imp = method_getImplementation(method)
class_replaceMethod(UITabBarItem.self, selector, imp_implementationWithBlock({ (self: UITabBarItem, image: UIImage?) -> Void in
if object_getClass(image) == DMDynamicImageProxy.self {
self.dm_dynamicSelectedImage = image
}
else {
self.dm_dynamicSelectedImage = nil
}
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UITabBarItem, Selector, UIImage?) -> Void).self)
oldIMP(self, selector, image)
} as @convention(block) (UITabBarItem, UIImage?) -> Void), method_getTypeEncoding(method))
}() }()
open func dmTraitCollectionDidChange(_ previousTraitCollection: DMTraitCollection?) { open func dmTraitCollectionDidChange(_ previousTraitCollection: DMTraitCollection?) {
@ -58,24 +86,4 @@ extension UITabBarItem: DMTraitEnvironment {
} }
} }
@objc dynamic func dm_setImage(_ image: UIImage?) {
if object_getClass(image) == DMDynamicImageProxy.self {
dm_dynamicImage = image
}
else {
dm_dynamicImage = nil
}
dm_setImage(image)
}
@objc dynamic func dm_setSelectedImage(_ image: UIImage?) {
if object_getClass(image) == DMDynamicImageProxy.self {
dm_dynamicSelectedImage = image
}
else {
dm_dynamicSelectedImage = nil
}
dm_setSelectedImage(image)
}
} }

Просмотреть файл

@ -26,16 +26,20 @@ extension UITextField {
/// `UITextField` will not call `super.willMove(toWindow:)` in its implementation, so we need to swizzle it separately. /// `UITextField` will not call `super.willMove(toWindow:)` in its implementation, so we need to swizzle it separately.
static let swizzleTextFieldWillMoveToWindowOnce: Void = { static let swizzleTextFieldWillMoveToWindowOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(willMove(toWindow:)), to: #selector(dm_textFieldWillMove(toWindow:))) { let selector = #selector(willMove(toWindow:))
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITextField.self, selector: #selector(willMove(toWindow:)))) guard let method = class_getInstanceMethod(UITextField.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITextField.self, selector: selector))
return
} }
}()
@objc private dynamic func dm_textFieldWillMove(toWindow window: UIWindow?) { let imp = method_getImplementation(method)
dm_textFieldWillMove(toWindow: window) class_replaceMethod(UITextField.self, selector, imp_implementationWithBlock({ (self: UITextField, window: UIWindow?) -> Void in
if window != nil { let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UITextField, Selector, UIWindow?) -> Void).self)
dm_updateDynamicColors() oldIMP(self, selector, window)
dm_updateDynamicImages() if window != nil {
} self.dm_updateDynamicColors()
} self.dm_updateDynamicImages()
}
} as @convention(block) (UITextField, UIWindow?) -> Void), method_getTypeEncoding(method))
}()
} }

Просмотреть файл

@ -28,18 +28,22 @@ extension UIView: DMTraitEnvironment {
extension UIView { extension UIView {
static let swizzleWillMoveToWindowOnce: Void = { static let swizzleWillMoveToWindowOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(willMove(toWindow:)), to: #selector(dm_willMove(toWindow:))) { let selector = #selector(willMove(toWindow:))
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: #selector(willMove(toWindow:)))) guard let method = class_getInstanceMethod(UIView.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: selector))
return
} }
}()
@objc private dynamic func dm_willMove(toWindow window: UIWindow?) { let imp = method_getImplementation(method)
dm_willMove(toWindow: window) class_replaceMethod(UIView.self, selector, imp_implementationWithBlock({ (self: UIView, window: UIWindow?) -> Void in
if window != nil { let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIView, Selector, UIWindow?) -> Void).self)
dm_updateDynamicColors() oldIMP(self, selector, window)
dm_updateDynamicImages() if window != nil {
} self.dm_updateDynamicColors()
} self.dm_updateDynamicImages()
}
} as @convention(block) (UIView, UIWindow?) -> Void), method_getTypeEncoding(method))
}()
} }
extension UIView { extension UIView {
@ -48,18 +52,22 @@ extension UIView {
} }
static let swizzleSetTintColorOnce: Void = { static let swizzleSetTintColorOnce: Void = {
if !dm_swizzleInstanceMethod(#selector(setter: tintColor), to: #selector(dm_setTintColor)) { let selector = #selector(setter: tintColor)
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: #selector(setter: tintColor))) guard let method = class_getInstanceMethod(UIView.self, selector) else {
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: selector))
return
} }
let imp = method_getImplementation(method)
class_replaceMethod(UIView.self, selector, imp_implementationWithBlock({ (self: UIView, tintColor: UIColor) -> Void in
self.dm_dynamicTintColor = tintColor as? DynamicColor
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIView, Selector, UIColor) -> Void).self)
oldIMP(self, selector, tintColor)
} as @convention(block) (UIView, UIColor) -> Void), method_getTypeEncoding(method))
}() }()
private var dm_dynamicTintColor: DynamicColor? { private var dm_dynamicTintColor: DynamicColor? {
get { return objc_getAssociatedObject(self, &Constants.dynamicTintColorKey) as? DynamicColor } get { return objc_getAssociatedObject(self, &Constants.dynamicTintColorKey) as? DynamicColor }
set { objc_setAssociatedObject(self, &Constants.dynamicTintColorKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } set { objc_setAssociatedObject(self, &Constants.dynamicTintColorKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
} }
@objc private dynamic func dm_setTintColor(_ color: UIColor) {
dm_dynamicTintColor = color as? DynamicColor
dm_setTintColor(color)
}
} }

Просмотреть файл

@ -15,6 +15,7 @@ final class MainViewController: ViewController {
Row(name: "UIView", vcType: UIViewVC.self), Row(name: "UIView", vcType: UIViewVC.self),
Row(name: "UIActivityIndicatorView", vcType: UIActivityIndicatorViewVC.self), Row(name: "UIActivityIndicatorView", vcType: UIActivityIndicatorViewVC.self),
Row(name: "UIButton", vcType: UIButtonVC.self), Row(name: "UIButton", vcType: UIButtonVC.self),
Row(name: "UILabel", vcType: UILabelVC.self),
Row(name: "UIPageControl", vcType: UIPageControlVC.self) Row(name: "UIPageControl", vcType: UIPageControlVC.self)
] ]

Просмотреть файл

@ -0,0 +1,30 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
import FluentDarkModeKit
final class UILabelVC: ViewController {
let label: UILabel = {
let label = UILabel()
label.text = "Test"
label.textColor = UIColor(.dm, light: .red, dark: .green)
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(.dm, light: .white, dark: .black)
view.addSubview(label)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
label.sizeToFit()
label.center = view.center
}
}