Skip to content

Commit

Permalink
Patch handling of reference cycles.
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher-Thiebaut committed Nov 28, 2020
1 parent 9500308 commit 99e325d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
7 changes: 5 additions & 2 deletions Sources/Container/Container.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,16 @@ public class Container {

/// Call `fill` to associate an instance of `Container` with an already created object and its descandants in the object tree. Any properties of the object that are marked as `@Containerized` will be resolved from this container
///
///
/// NOTE: Properties marked as `lazy` and their descendants will not be associated with the container. To get around this issue, keep your non-containerized properties lightweight and allow them to be constructed eagerly. `@Containerized` properties will be initialized lazily.
/// - Parameter object: The root of the object tree to be associated with the container
public func fill<T>(_ object: T) {
public func fill<T>(_ object: T, filledObjects: [AnyObject] = []) {
let mirror = Mirror(reflecting: object)
for child in mirror.children {
guard let containing = child.value as? ContainerHolder else {
fill(child.value)
let reference = child.value as AnyObject
guard !filledObjects.contains(where: { $0 === reference} ) else { continue }
fill(child.value, filledObjects: filledObjects + [reference])
continue
}
containing.container.value = self
Expand Down
29 changes: 29 additions & 0 deletions Tests/ContainerTests/ContainerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,35 @@ final class ContainerTests: XCTestCase {
XCTAssertEqual(store.greeter.greet(), "Hello, Containers!")
}

func testRecursiveDeathSpiral() throws {
//Note: This is an intentional reference cycle to test the container's handling of reference cycles. (Some reactive libraries have intentional reference cycles)
class HostileRecursiveExample {
let greeting = "Hello, World"
var child: ParentReferentialThing?

class ParentReferentialThing {
var parent: HostileRecursiveExample

init(parent: HostileRecursiveExample) {
self.parent = parent
}
}

init() {
child = ParentReferentialThing(parent: self)
}
}

class Greeter {
@Containerized var message: HostileRecursiveExample
}

subject.bind { HostileRecursiveExample() }
subject.bind { Greeter() }

let greeter: Greeter = try subject.resolve()
XCTAssertEqual(greeter.message.greeting, "Hello, World")
}


static var allTests = [
Expand Down

0 comments on commit 99e325d

Please sign in to comment.