From 00a11207770af46ed74de1b3b60f5b3a243c184a Mon Sep 17 00:00:00 2001 From: Jared Friese <jared.friese@gmail.com> Date: Mon, 3 Apr 2017 22:56:36 -0700 Subject: [PATCH] Convert `UIAlertAction` swizzling to better, more Swift-dependent method [#142848761] --- Fleet.xcodeproj/project.pbxproj | 8 +-- .../Alerts/UIAlertAction+Fleet.h | 7 --- .../Alerts/UIAlertAction+Fleet.m | 58 ++----------------- .../Alerts/UIAlertAction+Fleet.swift | 47 +++++++++++++++ Fleet/Fleet.h | 1 - 5 files changed, 56 insertions(+), 65 deletions(-) delete mode 100644 Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.h create mode 100644 Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.swift diff --git a/Fleet.xcodeproj/project.pbxproj b/Fleet.xcodeproj/project.pbxproj index fcf7329..32ff553 100644 --- a/Fleet.xcodeproj/project.pbxproj +++ b/Fleet.xcodeproj/project.pbxproj @@ -57,7 +57,6 @@ 7BB14A701D77B425002ABE82 /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BB14A6D1D77B425002ABE82 /* Screen.swift */; }; 7BB14A711D77B425002ABE82 /* FLTScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BB14A6E1D77B425002ABE82 /* FLTScreen.swift */; }; 7BDB63B31E47725600515C22 /* FleetError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB63B21E47725600515C22 /* FleetError.swift */; }; - 7BDF61EA1E935B4600990588 /* UIAlertAction+Fleet.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BDF61E71E935B4600990588 /* UIAlertAction+Fleet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7BDF61EB1E935B4600990588 /* UIAlertAction+Fleet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61E81E935B4600990588 /* UIAlertAction+Fleet.m */; }; 7BDF61EC1E935B4600990588 /* UIAlertController+Fleet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61E91E935B4600990588 /* UIAlertController+Fleet.swift */; }; 7BDF61F01E935B7500990588 /* UIAlertAction+FleetSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61EE1E935B7500990588 /* UIAlertAction+FleetSpec.swift */; }; @@ -67,6 +66,7 @@ 7BDF61FA1E93685800990588 /* FleetSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61F91E93685800990588 /* FleetSwizzle.m */; }; 7BDF61FC1E93691200990588 /* UITableViewRowAction+Fleet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61FB1E93691200990588 /* UITableViewRowAction+Fleet.m */; }; 7BDF61FE1E936A3200990588 /* UIStoryboard+Fleet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61FD1E936A3200990588 /* UIStoryboard+Fleet.m */; }; + 7BDF62001E936BFB00990588 /* UIAlertAction+Fleet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDF61FF1E936BFB00990588 /* UIAlertAction+Fleet.swift */; }; 7BEE35B51E15434A00302991 /* UITableView+SelectRowMinimalDelegateImplSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEE35B41E15434A00302991 /* UITableView+SelectRowMinimalDelegateImplSpec.swift */; }; 7BF913981E384A4E00019CF2 /* TableViewError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BF913971E384A4E00019CF2 /* TableViewError.swift */; }; 7BF913AE1E3A4BA800019CF2 /* UIViewController+Fleet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BF913AD1E3A4BA800019CF2 /* UIViewController+Fleet.swift */; }; @@ -164,7 +164,6 @@ 7BB14A6D1D77B425002ABE82 /* Screen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = "<group>"; }; 7BB14A6E1D77B425002ABE82 /* FLTScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FLTScreen.swift; sourceTree = "<group>"; }; 7BDB63B21E47725600515C22 /* FleetError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FleetError.swift; sourceTree = "<group>"; }; - 7BDF61E71E935B4600990588 /* UIAlertAction+Fleet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertAction+Fleet.h"; sourceTree = "<group>"; }; 7BDF61E81E935B4600990588 /* UIAlertAction+Fleet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertAction+Fleet.m"; sourceTree = "<group>"; }; 7BDF61E91E935B4600990588 /* UIAlertController+Fleet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Fleet.swift"; sourceTree = "<group>"; }; 7BDF61EE1E935B7500990588 /* UIAlertAction+FleetSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertAction+FleetSpec.swift"; sourceTree = "<group>"; }; @@ -175,6 +174,7 @@ 7BDF61F91E93685800990588 /* FleetSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FleetSwizzle.m; sourceTree = "<group>"; }; 7BDF61FB1E93691200990588 /* UITableViewRowAction+Fleet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableViewRowAction+Fleet.m"; sourceTree = "<group>"; }; 7BDF61FD1E936A3200990588 /* UIStoryboard+Fleet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIStoryboard+Fleet.m"; sourceTree = "<group>"; }; + 7BDF61FF1E936BFB00990588 /* UIAlertAction+Fleet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertAction+Fleet.swift"; sourceTree = "<group>"; }; 7BEE35B41E15434A00302991 /* UITableView+SelectRowMinimalDelegateImplSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITableView+SelectRowMinimalDelegateImplSpec.swift"; sourceTree = "<group>"; }; 7BF913971E384A4E00019CF2 /* TableViewError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewError.swift; sourceTree = "<group>"; }; 7BF913AD1E3A4BA800019CF2 /* UIViewController+Fleet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Fleet.swift"; sourceTree = "<group>"; }; @@ -508,8 +508,8 @@ 7BDF61E61E935B0E00990588 /* Alerts */ = { isa = PBXGroup; children = ( - 7BDF61E71E935B4600990588 /* UIAlertAction+Fleet.h */, 7BDF61E81E935B4600990588 /* UIAlertAction+Fleet.m */, + 7BDF61FF1E936BFB00990588 /* UIAlertAction+Fleet.swift */, 7BDF61E91E935B4600990588 /* UIAlertController+Fleet.swift */, ); path = Alerts; @@ -593,7 +593,6 @@ files = ( 7BA90AB71CC130990040B031 /* Fleet.h in Headers */, 7B8F2B3B1DE2592C00B6F4C2 /* FleetObjC.h in Headers */, - 7BDF61EA1E935B4600990588 /* UIAlertAction+Fleet.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -789,6 +788,7 @@ 7BB14A711D77B425002ABE82 /* FLTScreen.swift in Sources */, 7B675E941D0DA7EA002E6B45 /* Fleet.swift in Sources */, 7B9458101D4D7DFA00F16A64 /* StoryboardDeserializer.swift in Sources */, + 7BDF62001E936BFB00990588 /* UIAlertAction+Fleet.swift in Sources */, 7BDF61EB1E935B4600990588 /* UIAlertAction+Fleet.m in Sources */, 7B8F2B3C1DE2592C00B6F4C2 /* FleetObjC.m in Sources */, 7BFABD5C1E3DA2CD002823B3 /* UIButton+Fleet.swift in Sources */, diff --git a/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.h b/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.h deleted file mode 100644 index 6e42199..0000000 --- a/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.h +++ /dev/null @@ -1,7 +0,0 @@ -#import <UIKit/UIKit.h> - -@interface UIAlertAction (Fleet) - -@property (nonatomic, copy, readonly) void(^handler)(UIAlertAction *); - -@end diff --git a/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.m b/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.m index 39cd3b3..f44783b 100644 --- a/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.m +++ b/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.m @@ -1,69 +1,21 @@ -#import "UIAlertAction+Fleet.h" -#import <objc/runtime.h> - -@interface ObjectifiedBlock : NSObject - -@property (nonatomic, copy) void (^block)(UIAlertAction *); - -- (instancetype)initWithBlock:(void (^)(UIAlertAction *))block; - -@end - -@implementation ObjectifiedBlock - -- (instancetype)initWithBlock:(void (^)(UIAlertAction *))block { - if (self == [super init]) { - self.block = block; - } - - return self; -} - -@end +#import <UIKit/UIKit.h> +#import "FleetSwizzle.h" BOOL didSwizzleUIAlertAction = NO; -unsigned int handlerAssociatedKey = 0; - -@interface UIAlertAction (FleetPrivate) - -@property (nonatomic, copy) void (^fleet_property_handler)(UIAlertAction *); - -@end @implementation UIAlertAction (FleetPrivate) + (void)initialize { if (self == [UIAlertAction class]) { if (!didSwizzleUIAlertAction) { - [self swizzleHandlerSettler]; + [self objc_swizzleHandlerSetter]; didSwizzleUIAlertAction = YES; } } } -+ (void)swizzleHandlerSettler { - SEL originalSelector = NSSelectorFromString(@"setHandler:"); - SEL swizzledSelector = @selector(fleet_setHandler:); - - Method originalMethod = class_getInstanceMethod(self, originalSelector); - Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector); - - method_exchangeImplementations(originalMethod, swizzledMethod); -} - -- (void)fleet_setHandler:(void (^)(UIAlertAction *))handler { - self.fleet_property_handler = handler; - [self fleet_setHandler: handler]; -} - -- (void (^)(UIAlertAction *))fleet_property_handler { - ObjectifiedBlock *block = objc_getAssociatedObject(self, &handlerAssociatedKey); - return [block block]; -} - -- (void)setFleet_property_handler:(void (^)(UIAlertAction *))fleet_property_handler { - ObjectifiedBlock *block = [[ObjectifiedBlock alloc] initWithBlock: fleet_property_handler]; - objc_setAssociatedObject(self, &handlerAssociatedKey, block, OBJC_ASSOCIATION_RETAIN); ++ (void)objc_swizzleHandlerSetter { + memorySafeExecuteSelector(self, NSSelectorFromString(@"swizzleHandlerSetter")); } @end diff --git a/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.swift b/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.swift new file mode 100644 index 0000000..5cf8558 --- /dev/null +++ b/Fleet/CoreExtensions/Alerts/UIAlertAction+Fleet.swift @@ -0,0 +1,47 @@ +import UIKit +import ObjectiveC + +private var handlerAssociatedKey: UInt = 0 + +@objc private class ObjectifiedBlock: NSObject { + var block: ((UIAlertAction) -> Void)? + + init(block: ((UIAlertAction) -> Void)?) { + self.block = block + } +} + +extension UIAlertAction { + var handler: ((UIAlertAction) -> Void)? { + get { + return fleet_property_handler + } + } + + @objc class func swizzleHandlerSetter() { + let originalSelector = Selector(("setHandler:")) + let swizzledSelector = #selector(UIAlertAction.fleet_setHandler(_:)) + + let originalMethod = class_getInstanceMethod(self, originalSelector) + let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) + + method_exchangeImplementations(originalMethod, swizzledMethod) + } + + func fleet_setHandler(_ handler: ((UIAlertAction) -> Void)?) { + fleet_property_handler = handler + fleet_setHandler(handler) + } + + fileprivate var fleet_property_handler: ((UIAlertAction) -> Void)? { + get { + let block = objc_getAssociatedObject(self, &handlerAssociatedKey) as? ObjectifiedBlock + return block?.block + } + + set { + let block = ObjectifiedBlock(block: newValue) + objc_setAssociatedObject(self, &handlerAssociatedKey, block, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) + } + } +} diff --git a/Fleet/Fleet.h b/Fleet/Fleet.h index 7ca779a..7a57550 100644 --- a/Fleet/Fleet.h +++ b/Fleet/Fleet.h @@ -1,6 +1,5 @@ #import <UIKit/UIKit.h> #import "FleetObjC.h" -#import "UIAlertAction+Fleet.h" FOUNDATION_EXPORT double FleetVersionNumber; FOUNDATION_EXPORT const unsigned char FleetVersionString[];