Skip to content

Commit ee3121f

Browse files
committed
Updated to Swift 5
1 parent c52df80 commit ee3121f

6 files changed

Lines changed: 144 additions & 65 deletions

File tree

.gitignore

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
2+
# Created by https://www.gitignore.io/api/xcode,macos,swift,swiftpm,swiftpackagemanager
3+
# Edit at https://www.gitignore.io/?templates=xcode,macos,swift,swiftpm,swiftpackagemanager
4+
5+
### macOS ###
6+
# General
7+
.DS_Store
8+
.AppleDouble
9+
.LSOverride
10+
11+
# Icon must end with two \r
12+
Icon
13+
14+
# Thumbnails
15+
._*
16+
17+
# Files that might appear in the root of a volume
18+
.DocumentRevisions-V100
19+
.fseventsd
20+
.Spotlight-V100
21+
.TemporaryItems
22+
.Trashes
23+
.VolumeIcon.icns
24+
.com.apple.timemachine.donotpresent
25+
26+
# Directories potentially created on remote AFP share
27+
.AppleDB
28+
.AppleDesktop
29+
Network Trash Folder
30+
Temporary Items
31+
.apdisk
32+
33+
### Swift ###
134
# Xcode
235
#
336
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
@@ -19,7 +52,8 @@ xcuserdata/
1952

2053
## Other
2154
*.moved-aside
22-
*.xcuserstate
55+
*.xccheckout
56+
*.xcscmblueprint
2357

2458
## Obj-C/Swift specific
2559
*.hmap
@@ -32,36 +66,76 @@ timeline.xctimeline
3266
playground.xcworkspace
3367

3468
# Swift Package Manager
35-
#
3669
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
3770
# Packages/
71+
# Package.pins
72+
# Package.resolved
3873
.build/
74+
# Add this line if you want to avoid checking in Xcode SPM integration.
75+
.swiftpm/xcode
3976

4077
# CocoaPods
41-
#
4278
# We recommend against adding the Pods directory to your .gitignore. However
4379
# you should judge for yourself, the pros and cons are mentioned at:
4480
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45-
#
4681
# Pods/
82+
# Add this line if you want to avoid checking in source code from the Xcode workspace
83+
# *.xcworkspace
4784

4885
# Carthage
49-
#
5086
# Add this line if you want to avoid checking in source code from Carthage dependencies.
5187
# Carthage/Checkouts
5288

5389
Carthage/Build
5490

91+
# Accio dependency management
92+
Dependencies/
93+
.accio/
94+
5595
# fastlane
56-
#
5796
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
5897
# screenshots whenever they are needed.
5998
# For more information about the recommended setup visit:
60-
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
99+
# https://docs.fastlane.tools/best-practices/source-control/#source-control
61100

62101
fastlane/report.xml
63102
fastlane/Preview.html
64-
fastlane/screenshots
103+
fastlane/screenshots/**/*.png
65104
fastlane/test_output
66-
ObjectiveKit.xcodeproj/project.xcworkspace/xcuserdata/marmelroy.xcuserdatad/UserInterfaceState.xcuserstate
67-
ObjectiveKit.xcodeproj/xcuserdata/marmelroy.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
105+
106+
# Code Injection
107+
# After new code Injection tools there's a generated folder /iOSInjectionProject
108+
# https://github.com/johnno1962/injectionforxcode
109+
110+
iOSInjectionProject/
111+
112+
### SwiftPackageManager ###
113+
Packages
114+
xcuserdata
115+
*.xcodeproj
116+
117+
118+
### SwiftPM ###
119+
120+
121+
### Xcode ###
122+
# Xcode
123+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
124+
125+
## User settings
126+
127+
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
128+
129+
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
130+
131+
## Xcode Patch
132+
*.xcodeproj/*
133+
!*.xcodeproj/project.pbxproj
134+
!*.xcodeproj/xcshareddata/
135+
!*.xcworkspace/contents.xcworkspacedata
136+
/*.gcno
137+
138+
### Xcode Patch ###
139+
**/xcshareddata/WorkspaceSettings.xcsettings
140+
141+
# End of https://www.gitignore.io/api/xcode,macos,swift,swiftpm,swiftpackagemanager

ObjectiveKit/ObjectiveClass.swift

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88

99
import Foundation
1010

11-
typealias ImplementationBlock = @convention(block) () -> Void
12-
1311
/// An object that allows you to introspect and modify classes through the ObjC runtime.
14-
public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
12+
public class ObjectiveClass<T: NSObject>: ObjectiveKitRuntimeModification {
1513

1614
public var internalClass: AnyClass
1715

@@ -33,7 +31,7 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
3331
var ivars = [String]()
3432
let ivarList = class_copyIvarList(internalClass, &count)
3533
for i in (0..<Int(count)) {
36-
let unwrapped = ivarList?[i].unsafelyUnwrapped
34+
let unwrapped = (ivarList?[i]).unsafelyUnwrapped
3735
if let ivar = ivar_getName(unwrapped) {
3836
let string = String(cString: ivar)
3937
ivars.append(string)
@@ -44,7 +42,6 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
4442
}
4543
}
4644

47-
4845
/// Get all selectors implemented by the class.
4946
///
5047
/// - Returns: An array of selectors.
@@ -54,8 +51,8 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
5451
var selectors = [Selector]()
5552
let methodList = class_copyMethodList(internalClass, &count)
5653
for i in (0..<Int(count)) {
57-
let unwrapped = methodList?[i].unsafelyUnwrapped
58-
if let selector = method_getName(unwrapped) {
54+
if let unwrapped = methodList?[i] {
55+
let selector = method_getName(unwrapped)
5956
selectors.append(selector)
6057
}
6158
}
@@ -73,8 +70,8 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
7370
var protocols = [String]()
7471
let protocolList = class_copyProtocolList(internalClass, &count)
7572
for i in (0..<Int(count)) {
76-
let unwrapped = protocolList?[i].unsafelyUnwrapped
77-
if let protocolName = protocol_getName(unwrapped) {
73+
if let unwrapped = protocolList?[i] {
74+
let protocolName = protocol_getName(unwrapped)
7875
let string = String(cString: protocolName)
7976
protocols.append(string)
8077
}
@@ -92,8 +89,8 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
9289
var properties = [String]()
9390
let propertyList = class_copyPropertyList(internalClass, &count)
9491
for i in (0..<Int(count)) {
95-
let unwrapped = propertyList?[i].unsafelyUnwrapped
96-
if let propretyName = property_getName(unwrapped) {
92+
if let unwrapped = propertyList?[i] {
93+
let propretyName = property_getName(unwrapped)
9794
let string = String(cString: propretyName)
9895
properties.append(string)
9996
}
@@ -102,7 +99,4 @@ public class ObjectiveClass <T: NSObject>: ObjectiveKitRuntimeModification {
10299
return properties
103100
}
104101
}
105-
106102
}
107-
108-

ObjectiveKit/RuntimeClass.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import Foundation
1010

1111
/// A class created at runtime.
1212
public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification {
13-
1413
public var internalClass: AnyClass
15-
1614
private var registered: Bool = false
1715

1816
// MARK: Lifecycle
@@ -22,7 +20,10 @@ public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification {
2220
/// - Parameter superclass: Superclass to inherit from.
2321
public init(superclass: AnyClass = NSObject.classForCoder()) {
2422
let name = NSUUID().uuidString
25-
self.internalClass = objc_allocateClassPair(superclass, name, 0)
23+
guard let internalClass = objc_allocateClassPair(superclass, name, 0) else {
24+
fatalError("The class '\(superclass)' could not be created")
25+
}
26+
self.internalClass = internalClass
2627
}
2728

2829
// MARK: Dynamic class creation
@@ -41,7 +42,6 @@ public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification {
4142
class_addIvar(self.internalClass, name, size, UInt8(alignment), rawEncoding)
4243
}
4344

44-
4545
/// Register class. Required before usage. Happens automatically on allocate.
4646
public func register() {
4747
if registered == false {
@@ -57,10 +57,8 @@ public class RuntimeClass: NSObject, ObjectiveKitRuntimeModification {
5757
self.register()
5858
return internalClass.alloc() as! NSObject
5959
}
60-
6160
}
6261

63-
6462
/// Objective Type
6563
///
6664
/// - NSString: NSString
@@ -87,6 +85,4 @@ public enum ObjectiveType: Int {
8785
case .Void: return "v"
8886
}
8987
}
90-
9188
}
92-

ObjectiveKit/RuntimeModification.swift

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import Foundation
1010

1111
public protocol ObjectiveKitRuntimeModification {
12-
1312
var internalClass: AnyClass { get }
1413

1514
// MARK: Runtime modification
@@ -26,50 +25,50 @@ public protocol ObjectiveKitRuntimeModification {
2625
/// - Parameters:
2726
/// - identifier: Selector name.
2827
/// - implementation: Implementation as a closure.
29-
func addMethod(_ identifier: String, implementation: ImplementationBlock)
28+
@discardableResult
29+
func addMethod(_ identifier: String, implementation: @escaping @convention(block) (AnyObject) -> Void) -> Selector
3030

3131
/// Exchange selectors implemented in the current class.
3232
///
3333
/// - Parameters:
3434
/// - aSelector: Selector.
3535
/// - otherSelector: Selector.
3636
func exchangeSelector(_ aSelector: Selector, with otherSelector: Selector)
37-
3837
}
3938

4039
extension ObjectiveKitRuntimeModification {
41-
4240
public func addSelector(_ selector: Selector, from originalClass: AnyClass) {
43-
guard let method = class_getInstanceMethod(originalClass, selector), let implementation = method_getImplementation(method), let typeEncoding = method_getTypeEncoding(method) else {
41+
guard let method = class_getInstanceMethod(originalClass, selector), let typeEncoding = method_getTypeEncoding(method) else {
4442
return
4543
}
44+
let implementation = method_getImplementation(method)
4645
let string = String(cString: typeEncoding)
4746
class_addMethod(internalClass, selector, implementation, string)
4847
}
4948

50-
public func addMethod(_ identifier: String, implementation: ImplementationBlock) {
51-
let blockObject = unsafeBitCast(implementation, to: AnyObject.self)
49+
@discardableResult
50+
public func addMethod(_ identifier: String, implementation: @escaping @convention(block) (AnyObject) -> Void) -> Selector {
51+
let blockObject = unsafeBitCast(implementation, to: NSObject.self)
5252
let implementation = imp_implementationWithBlock(blockObject)
5353
let selector = NSSelectorFromString(identifier)
5454
let encoding = "v@:f"
55-
class_addMethod(internalClass, selector, implementation, encoding)
55+
class_replaceMethod(internalClass, selector, implementation, encoding)
56+
return selector
5657
}
5758

5859
public func exchangeSelector(_ aSelector: Selector, with otherSelector: Selector) {
59-
let method = class_getInstanceMethod(internalClass, aSelector)
60-
let otherMethod = class_getInstanceMethod(internalClass, otherSelector)
60+
guard let method = class_getInstanceMethod(internalClass, aSelector), let otherMethod = class_getInstanceMethod(internalClass, otherSelector) else {
61+
return
62+
}
6163
method_exchangeImplementations(method, otherMethod)
6264
}
63-
6465
}
6566

6667
public extension NSObject {
67-
6868
/// A convenience method to perform selectors by identifier strings.
6969
///
7070
/// - Parameter identifier: Selector name.
71-
public func performMethod(_ identifier: String) {
71+
func performMethod(_ identifier: String) {
7272
perform(NSSelectorFromString(identifier))
7373
}
7474
}
75-

ObjectiveKitTests/ObjectiveKitTests.swift

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,20 @@
77
//
88

99
import XCTest
10-
import MapKit
1110
@testable import ObjectiveKit
1211

13-
@objc class Subview: UIView {
12+
@objc protocol CustomProtocol { }
1413

15-
dynamic func testSelector() {
16-
print("test selector")
17-
}
14+
class Subview: UIView, CustomProtocol {
15+
@objc var customVar = "something"
16+
@objc let customLet = "something"
1817

19-
dynamic func swizzledSelector(){
20-
print("swizzled selector")
18+
@objc func customSelector() {
19+
print("test selector")
2120
}
22-
2321
}
2422

25-
@objc class ObjectiveKitTests: XCTestCase {
26-
23+
class ObjectiveKitTests: XCTestCase {
2724
let closureName = "random"
2825

2926
dynamic func testSelector() {
@@ -33,7 +30,7 @@ import MapKit
3330
func testAddClosure() {
3431
let methodExpectation = expectation(description: "Method was called")
3532
let objectiveView = ObjectiveClass<UIView>()
36-
objectiveView.addMethod(closureName, implementation: {
33+
objectiveView.addMethod(closureName, implementation: { _ in
3734
methodExpectation.fulfill()
3835
})
3936
let view = UIView()
@@ -58,16 +55,14 @@ import MapKit
5855
}
5956

6057
func testIntrospection() {
61-
let objectiveView = ObjectiveClass<MKMapView>()
58+
let objectiveView = ObjectiveClass<Subview>()
6259
let ivars = objectiveView.ivars
63-
XCTAssert(ivars.contains("_camera"))
60+
XCTAssertEqual(ivars, ["customVar", "customLet"])
6461
let selectors = objectiveView.selectors
65-
XCTAssert(selectors.contains(NSSelectorFromString("layoutSubviews")))
62+
XCTAssertEqual(selectors.last, NSSelectorFromString("customSelector"))
6663
let protocols = objectiveView.protocols
67-
XCTAssert(protocols.contains("MKAnnotationManagerDelegate"))
64+
XCTAssertEqual(protocols, ["ObjectiveKitTests.CustomProtocol"])
6865
let properties = objectiveView.properties
69-
XCTAssert(properties.contains("mapRegion"))
66+
XCTAssertEqual(properties, ["customVar", "customLet"])
7067
}
71-
72-
7368
}

0 commit comments

Comments
 (0)