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[];