From 211a222428ea2bca8d035597abdd590757dfe68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81s=20Cecilia=20Luque?= Date: Mon, 13 Apr 2020 17:52:17 +0200 Subject: [PATCH] Updated to Swift 5 --- .gitignore | 94 +++++++++++++++++++++++--- ObjectiveKit/ObjectiveClass.swift | 22 +++--- ObjectiveKit/RuntimeClass.swift | 12 ++-- ObjectiveKit/RuntimeModification.swift | 27 ++++---- Package.swift | 23 ++++++- 5 files changed, 131 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index d2f3659..dc71f21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,36 @@ + +# Created by https://www.gitignore.io/api/xcode,macos,swift,swiftpm,swiftpackagemanager +# Edit at https://www.gitignore.io/?templates=xcode,macos,swift,swiftpm,swiftpackagemanager + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Swift ### # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore @@ -19,7 +52,8 @@ xcuserdata/ ## Other *.moved-aside -*.xcuserstate +*.xccheckout +*.xcscmblueprint ## Obj-C/Swift specific *.hmap @@ -32,36 +66,76 @@ timeline.xctimeline playground.xcworkspace # Swift Package Manager -# # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ +# Package.pins +# Package.resolved .build/ +# Add this line if you want to avoid checking in Xcode SPM integration. +.swiftpm/xcode # CocoaPods -# # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# # Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace # Carthage -# # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build +# Accio dependency management +Dependencies/ +.accio/ + # fastlane -# # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md +# https://docs.fastlane.tools/best-practices/source-control/#source-control fastlane/report.xml fastlane/Preview.html -fastlane/screenshots +fastlane/screenshots/**/*.png fastlane/test_output -ObjectiveKit.xcodeproj/project.xcworkspace/xcuserdata/marmelroy.xcuserdatad/UserInterfaceState.xcuserstate -ObjectiveKit.xcodeproj/xcuserdata/marmelroy.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### SwiftPackageManager ### +Packages +xcuserdata +*.xcodeproj + + +### SwiftPM ### + + +### Xcode ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) + +## Xcode Patch +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### Xcode Patch ### +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.gitignore.io/api/xcode,macos,swift,swiftpm,swiftpackagemanager \ No newline at end of file diff --git a/ObjectiveKit/ObjectiveClass.swift b/ObjectiveKit/ObjectiveClass.swift index a9cd787..1c651c7 100644 --- a/ObjectiveKit/ObjectiveClass.swift +++ b/ObjectiveKit/ObjectiveClass.swift @@ -8,10 +8,8 @@ import Foundation -typealias ImplementationBlock = @convention(block) () -> Void - /// An object that allows you to introspect and modify classes through the ObjC runtime. -public class ObjectiveClass : ObjectiveKitRuntimeModification { +public class ObjectiveClass: ObjectiveKitRuntimeModification { public var internalClass: AnyClass @@ -33,7 +31,7 @@ public class ObjectiveClass : ObjectiveKitRuntimeModification { var ivars = [String]() let ivarList = class_copyIvarList(internalClass, &count) for i in (0..: ObjectiveKitRuntimeModification { } } - /// Get all selectors implemented by the class. /// /// - Returns: An array of selectors. @@ -54,8 +51,8 @@ public class ObjectiveClass : ObjectiveKitRuntimeModification { var selectors = [Selector]() let methodList = class_copyMethodList(internalClass, &count) for i in (0..: ObjectiveKitRuntimeModification { var protocols = [String]() let protocolList = class_copyProtocolList(internalClass, &count) for i in (0..: ObjectiveKitRuntimeModification { var properties = [String]() let propertyList = class_copyPropertyList(internalClass, &count) for i in (0..: ObjectiveKitRuntimeModification { return properties } } - } - - diff --git a/ObjectiveKit/RuntimeClass.swift b/ObjectiveKit/RuntimeClass.swift index 13ab0c4..7bde315 100644 --- a/ObjectiveKit/RuntimeClass.swift +++ b/ObjectiveKit/RuntimeClass.swift @@ -10,9 +10,7 @@ import Foundation /// A class created at runtime. public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification { - public var internalClass: AnyClass - private var registered: Bool = false // MARK: Lifecycle @@ -22,7 +20,10 @@ public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification { /// - Parameter superclass: Superclass to inherit from. public init(superclass: AnyClass = NSObject.classForCoder()) { let name = NSUUID().uuidString - self.internalClass = objc_allocateClassPair(superclass, name, 0) + guard let internalClass = objc_allocateClassPair(superclass, name, 0) else { + fatalError("The class '\(superclass)' could not be created") + } + self.internalClass = internalClass } // MARK: Dynamic class creation @@ -41,7 +42,6 @@ public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification { class_addIvar(self.internalClass, name, size, UInt8(alignment), rawEncoding) } - /// Register class. Required before usage. Happens automatically on allocate. public func register() { if registered == false { @@ -57,10 +57,8 @@ public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification { self.register() return internalClass.alloc() as! NSObject } - } - /// Objective Type /// /// - NSString: NSString @@ -87,6 +85,4 @@ public enum ObjectiveType: Int { case .Void: return "v" } } - } - diff --git a/ObjectiveKit/RuntimeModification.swift b/ObjectiveKit/RuntimeModification.swift index bd2f2c8..9d6d3be 100644 --- a/ObjectiveKit/RuntimeModification.swift +++ b/ObjectiveKit/RuntimeModification.swift @@ -9,7 +9,6 @@ import Foundation public protocol ObjectiveKitRuntimeModification { - var internalClass: AnyClass { get } // MARK: Runtime modification @@ -26,7 +25,8 @@ public protocol ObjectiveKitRuntimeModification { /// - Parameters: /// - identifier: Selector name. /// - implementation: Implementation as a closure. - func addMethod(_ identifier: String, implementation: ImplementationBlock) + @discardableResult + func addMethod(_ identifier: String, implementation: @escaping @convention(block) (AnyObject) -> Void) -> Selector /// Exchange selectors implemented in the current class. /// @@ -34,42 +34,41 @@ public protocol ObjectiveKitRuntimeModification { /// - aSelector: Selector. /// - otherSelector: Selector. func exchangeSelector(_ aSelector: Selector, with otherSelector: Selector) - } extension ObjectiveKitRuntimeModification { - public func addSelector(_ selector: Selector, from originalClass: AnyClass) { - guard let method = class_getInstanceMethod(originalClass, selector), let implementation = method_getImplementation(method), let typeEncoding = method_getTypeEncoding(method) else { + guard let method = class_getInstanceMethod(originalClass, selector), let typeEncoding = method_getTypeEncoding(method) else { return } + let implementation = method_getImplementation(method) let string = String(cString: typeEncoding) class_addMethod(internalClass, selector, implementation, string) } - public func addMethod(_ identifier: String, implementation: ImplementationBlock) { - let blockObject = unsafeBitCast(implementation, to: AnyObject.self) + @discardableResult + public func addMethod(_ identifier: String, implementation: @escaping @convention(block) (AnyObject) -> Void) -> Selector { + let blockObject = unsafeBitCast(implementation, to: NSObject.self) let implementation = imp_implementationWithBlock(blockObject) let selector = NSSelectorFromString(identifier) let encoding = "v@:f" - class_addMethod(internalClass, selector, implementation, encoding) + class_replaceMethod(internalClass, selector, implementation, encoding) + return selector } public func exchangeSelector(_ aSelector: Selector, with otherSelector: Selector) { - let method = class_getInstanceMethod(internalClass, aSelector) - let otherMethod = class_getInstanceMethod(internalClass, otherSelector) + guard let method = class_getInstanceMethod(internalClass, aSelector), let otherMethod = class_getInstanceMethod(internalClass, otherSelector) else { + return + } method_exchangeImplementations(method, otherMethod) } - } public extension NSObject { - /// A convenience method to perform selectors by identifier strings. /// /// - Parameter identifier: Selector name. - public func performMethod(_ identifier: String) { + func performMethod(_ identifier: String) { perform(NSSelectorFromString(identifier)) } } - diff --git a/Package.swift b/Package.swift index 00b574d..b60a9c0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,5 +1,26 @@ +// swift-tools-version:5.2 +// The swift-tools-version declares the minimum version of Swift required to build this package. + import PackageDescription let package = Package( - name: "Interpolate" + name: "ObjectiveKit", + products: [ + .library(name: "ObjectiveKit", targets: ["ObjectiveKit"]), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "ObjectiveKit", + path: "ObjectiveKit" + ), + .testTarget( + name: "ObjectiveKitTests", + dependencies: [ + "ObjectiveKit" + ], + path: "ObjectiveKitTests" + ), + ] )