Skip to content

Commit 1afbefe

Browse files
author
Hadevs
committed
add each over classes reference without recursive fatall error
1 parent 5387b3b commit 1afbefe

File tree

4 files changed

+96
-8
lines changed

4 files changed

+96
-8
lines changed

SwiftInjector/SwiftInjector/AppDelegate.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
1616

1717

1818
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
19-
let newVc: ViewController? = container.resolve(name: "123")
19+
let newVc: ViewController? = self.container.resolve(name: "123")
2020
let testClass = newVc?.testClass
2121

22-
2322
print(testClass)
2423
return true
2524
}

SwiftInjector/SwiftInjector/Source/Containerable.swift

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ protocol Containerable: class {
1212
typealias Object = AnyObject
1313
typealias ServiceName = String
1414
typealias Service = (() -> Object)
15+
typealias RelationIn = String
16+
typealias RelationOut = String
17+
1518
var container: Containerable? { get set }
1619
var dispatchRegistrationGroup: DispatchGroup { get }
1720

1821
var services: [ServiceName: [ContainerObject]] { get set }
22+
var relations: [RelationIn: [RelationOut]] { get set }
23+
var recursiveNotResolvedObjects: [Object] { get set }
1924
}
2025

2126
struct ContainerObject {
@@ -30,7 +35,6 @@ struct ContainerObject {
3035

3136
extension Containerable {
3237
private func resolveAny(typeString: String, name: String? = nil) -> Object? {
33-
// TODO: replace .first with more smart condition
3438
let array: [ContainerObject]? = {
3539
if let filterName = name {
3640
return services[typeString]?.filter { $0.name == filterName }
@@ -40,19 +44,22 @@ extension Containerable {
4044
}()
4145

4246
if (array?.count ?? 0) > 1 {
43-
SILogger("Warning in \(typeString) resolving. You registered two different object for this type. Try to provide \"name\" argument while registering your object. But you will receive first object of all services you registered.").log()
47+
SILogger("Warning in \(typeString) resolving. You registered two different objects for this type. Try to provide \"name\" argument while registering your object. But you will receive first object of all services you registered.").log(priority: .high)
4448
}
4549

4650
if let object = array?.first?.object {
47-
autoresolve(on: object)
4851
return object
4952
} else if let object = array?.first?.registration() {
53+
5054
var objects = services[typeString]
5155
if objects?.count ?? 0 > 0 {
5256
objects?[0].object = object
5357
}
58+
5459
services[typeString] = objects ?? []
5560
autoresolve(on: object)
61+
finishRegistrations()
62+
5663
return object
5764
} else {
5865
return nil
@@ -66,14 +73,33 @@ extension Containerable {
6673
return object
6774
}
6875

76+
func finishRegistrations() {
77+
relations = [:]
78+
for object in recursiveNotResolvedObjects {
79+
autoresolve(on: object)
80+
}
81+
recursiveNotResolvedObjects.removeAll()
82+
}
83+
6984
private func autoresolve<T: Object>(on object: T) {
7085
let mirror = Mirror(reflecting: object)
86+
7187
for attr in mirror.children {
7288
if let property_name = attr.label {
7389
let objectType = type(of: attr.value)
7490
let typeString = String(describing: objectType).replacingOccurrences(of: "Optional<", with: "").replacingOccurrences(of: ">", with: "")
91+
92+
// MARK: MUTATE VARIABLE (DANGER OBJC RUNTIME ZONE)
7593
if let ivar = class_getInstanceVariable(type(of: object), property_name) {
76-
print(type(of: object), mirror.children.map { $0.label })
94+
let typeStringOfMyObject = formattedString(of: object)
95+
recordRelations(relationIn: typeString, relationOut: typeStringOfMyObject)
96+
if relations[typeStringOfMyObject]?.contains(typeString) ?? false {
97+
relations[typeString]?.removeAll(where: { (string) -> Bool in
98+
return string == typeStringOfMyObject
99+
})
100+
recursiveNotResolvedObjects.append(object)
101+
return
102+
}
77103
if let value = resolveAny(typeString: typeString) {
78104
object_setIvar(object, ivar, value)
79105
}
@@ -82,6 +108,61 @@ extension Containerable {
82108
}
83109
}
84110

111+
private func memmoryAddress(_ object: Object) -> String {
112+
return "\(Unmanaged.passUnretained(object).toOpaque())"
113+
}
114+
115+
private func recordRelations(relationIn: RelationIn, relationOut: RelationOut) {
116+
if let relationsOut = relations[relationIn], !relationsOut.contains(relationOut) {
117+
var newRelationsOut = relationsOut
118+
newRelationsOut.append(relationOut)
119+
relations[relationIn] = newRelationsOut
120+
} else {
121+
relations[relationIn] = [relationOut]
122+
}
123+
}
124+
125+
private func formattedString<T: Object>(of object: T) -> String {
126+
return String(describing: type(of: object)).replacingOccurrences(of: "Optional<", with: "").replacingOccurrences(of: ">", with: "")
127+
}
128+
129+
private func doesObjectHas(object: Object, propertyType: String) -> Bool {
130+
let mirror = Mirror(reflecting: object)
131+
for attr in mirror.children {
132+
let objectType = type(of: attr.value)
133+
let typeString = String(describing: objectType).replacingOccurrences(of: "Optional<", with: "").replacingOccurrences(of: ">", with: "")
134+
if typeString == typeString {
135+
return true
136+
}
137+
}
138+
139+
return false
140+
}
141+
142+
private func property<T>(object: Object, propertyName: String) -> T? {
143+
let mirror = Mirror(reflecting: object)
144+
for attr in mirror.children {
145+
if attr.label == propertyName {
146+
return attr.value as? T
147+
}
148+
}
149+
150+
return nil
151+
}
152+
153+
private func propertyName(by typeString: String, in object: Object) -> String? {
154+
let mirror = Mirror(reflecting: object)
155+
for attr in mirror.children {
156+
let propertyType = type(of: attr.value)
157+
let typeStringInside = String(describing: propertyType).replacingOccurrences(of: "Optional<", with: "").replacingOccurrences(of: ">", with: "")
158+
if typeStringInside == typeString {
159+
return attr.label
160+
}
161+
}
162+
163+
return nil
164+
}
165+
85166
func register<T: Object>(_ registration: @escaping (() -> T), name: String? = nil) {
86167

87168
dispatchRegistrationGroup.enter()

SwiftInjector/SwiftInjector/Source/RootContainer.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@
99
import Foundation
1010

1111
class RootContainer: Containerable {
12-
var services: [ServiceName : [ContainerObject]] = [:]
12+
var recursiveNotResolvedObjects: [Object] = []
13+
14+
var relations: [RelationIn: [RelationOut]] = [:]
15+
var services: [ServiceName: [ContainerObject]] = [:]
1316

1417
var dispatchRegistrationGroup: DispatchGroup = DispatchGroup()
1518

1619
var container: Containerable?
1720

1821
init() {
22+
let date = Date()
1923
dispatchRegistrationGroup.notify(queue: .main) {
20-
print("All properties have been successfully injected.")
24+
25+
self.finishRegistrations()
26+
let seconds = Date().timeIntervalSince(date)
27+
print("All properties have been successfully injected for \(seconds) seconds.")
2128
}
2229
}
2330
}

SwiftInjector/SwiftInjector/TestClass.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ import Foundation
1010

1111
class TestClass {
1212
var name: String = "123"
13+
weak var viewController: ViewController?
1314
}

0 commit comments

Comments
 (0)