Skip to content

Commit

Permalink
Update Box for BoardProducer to avoid reference management
Browse files Browse the repository at this point in the history
  • Loading branch information
congncif committed Oct 1, 2021
1 parent e05459e commit af0073a
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Boardy.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Boardy"
s.version = "1.33.2"
s.version = "1.34.0"
s.swift_versions = ["5.3", "5.4", "5.5"]
s.summary = "A mediator interface to integrate multiple mobile architectures."

Expand Down
43 changes: 33 additions & 10 deletions Boardy/Core/Board/BoardProducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,16 @@ extension Array: BoardRegistrationsConvertible where Element == BoardRegistratio
public func asBoardRegistrations() -> [BoardRegistration] { self }
}

public protocol BoardDynamicProducer: AnyObject, ActivableBoardProducer {
public protocol BoardDynamicProducer: ActivableBoardProducer {
func registerBoard(_ identifier: BoardID, factory: @escaping (BoardID) -> ActivatableBoard)
}

public extension BoardDynamicProducer {
/// Boxed the producer as a ValueType without retaining to avoid working with reference counter
var boxed: ActivableBoardProducer {
return BoardProducerBox(producer: self)
}
}

public final class BoardProducer: BoardDynamicProducer {
public private(set) var registrations = Set<BoardRegistration>()

private var externalProducer: ActivableBoardProducer

public init(externalProducer: ActivableBoardProducer = NoBoardProducer(), registrations: [BoardRegistration]) {
public init(externalProducer: ActivableBoardProducer = NoBoardProducer(), registrations: [BoardRegistration] = []) {
self.externalProducer = externalProducer
self.registrations = Set(registrations)
}
Expand Down Expand Up @@ -79,8 +72,38 @@ public final class BoardProducer: BoardDynamicProducer {
}
}

public extension BoardDynamicProducer where Self: AnyObject {
/// Boxed the producer as a ValueType without retaining to avoid working with reference counter
var boxed: BoardDynamicProducer {
return BoardDynamicProducerBox(producer: self)
}
}

struct BoardDynamicProducerBox: BoardDynamicProducer {
weak var producer: (BoardDynamicProducer & AnyObject)?

func produceBoard(identifier: BoardID) -> ActivatableBoard? {
producer?.produceBoard(identifier: identifier)
}

func matchBoard(withIdentifier identifier: BoardID, to anotherIdentifier: BoardID) -> ActivatableBoard? {
producer?.matchBoard(withIdentifier: identifier, to: anotherIdentifier)
}

func registerBoard(_ identifier: BoardID, factory: @escaping (BoardID) -> ActivatableBoard) {
producer?.registerBoard(identifier, factory: factory)
}
}

public extension ActivableBoardProducer where Self: AnyObject {
/// Boxed the producer as a ValueType without retaining to avoid working with reference counter
var boxed: ActivableBoardProducer {
return BoardProducerBox(producer: self)
}
}

struct BoardProducerBox: ActivableBoardProducer {
weak var producer: BoardDynamicProducer?
weak var producer: (ActivableBoardProducer & AnyObject)?

func produceBoard(identifier: BoardID) -> ActivatableBoard? {
producer?.produceBoard(identifier: identifier)
Expand Down
2 changes: 1 addition & 1 deletion Boardy/Core/Board/BoardRegistrationBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extension Motherboard {
extension BoardProducer {
public convenience init(externalProducer: ActivableBoardProducer = NoBoardProducer(), @BoardRegistrationBuilder registrationsBuilder: (_ producer: ActivableBoardProducer) -> [BoardRegistration]) {
self.init(externalProducer: externalProducer, registrations: [])
let registrations = registrationsBuilder(BoardProducerBox(producer: self))
let registrations = registrationsBuilder(BoardDynamicProducerBox(producer: self))
for registration in registrations {
add(registration: registration)
}
Expand Down
8 changes: 4 additions & 4 deletions Boardy/ModulePlugin/PluginLauncher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
public final class LauncherComponent {
public let options: MainOptions

private var container = BoardProducer(registrations: [])
private var container = BoardProducer()

private var plugins: [ModulePlugin] = []

Expand Down Expand Up @@ -49,7 +49,7 @@ public final class LauncherComponent {

func generateMainboard() -> Motherboard {
loadPluginsIfNeeded()
return Motherboard(boardProducer: producer)
return Motherboard(boardProducer: container)
}

/// Create & return new instance of Launcher
Expand All @@ -64,7 +64,7 @@ public final class LauncherComponent {
}

extension LauncherComponent: MainComponent {
public var producer: BoardDynamicProducer { container }
public var producer: BoardDynamicProducer { container.boxed }
}

public final class PluginLauncher {
Expand All @@ -78,7 +78,7 @@ public final class PluginLauncher {

public static var shared: PluginLauncher {
guard let instance = sharedInstance else {
fatalError("PluginLauncher must be initialized before using")
preconditionFailure("PluginLauncher must be initialized before using")
}
return instance
}
Expand Down
4 changes: 4 additions & 0 deletions Example/Boardy.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
27058AE026DA4281008FB4F6 /* BarrierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27058ADF26DA4281008FB4F6 /* BarrierTests.swift */; };
27547FCE25415640005C9027 /* HeadlineBoard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27547FCD25415640005C9027 /* HeadlineBoard.swift */; };
27547FD22541571C005C9027 /* FeaturedBoard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27547FD12541571C005C9027 /* FeaturedBoard.swift */; };
2766A4652706B22300C04DA9 /* ProducerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2766A4642706B22300C04DA9 /* ProducerTests.swift */; };
2776F43126DD0F4900680B7F /* TaskBoardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2776F43026DD0F4900680B7F /* TaskBoardTests.swift */; };
277BC12926D9EEF400BDEA8F /* AdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277BC12826D9EEF400BDEA8F /* AdapterTests.swift */; };
277BC12B26D9F75C00BDEA8F /* InteractableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277BC12A26D9F75C00BDEA8F /* InteractableTests.swift */; };
Expand Down Expand Up @@ -100,6 +101,7 @@
27058ADF26DA4281008FB4F6 /* BarrierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarrierTests.swift; sourceTree = "<group>"; };
27547FCD25415640005C9027 /* HeadlineBoard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBoard.swift; sourceTree = "<group>"; };
27547FD12541571C005C9027 /* FeaturedBoard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedBoard.swift; sourceTree = "<group>"; };
2766A4642706B22300C04DA9 /* ProducerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProducerTests.swift; sourceTree = "<group>"; };
2776F43026DD0F4900680B7F /* TaskBoardTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskBoardTests.swift; sourceTree = "<group>"; };
277BC12826D9EEF400BDEA8F /* AdapterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdapterTests.swift; sourceTree = "<group>"; };
277BC12A26D9F75C00BDEA8F /* InteractableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractableTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -453,6 +455,7 @@
279F720B25CBC8E9000160C6 /* LifecycleTests.swift */,
2776F43026DD0F4900680B7F /* TaskBoardTests.swift */,
27F4F05726E499ED005BAC34 /* ResultBoardTests.swift */,
2766A4642706B22300C04DA9 /* ProducerTests.swift */,
607FACE91AFB9204008FA782 /* Supporting Files */,
);
path = Tests;
Expand Down Expand Up @@ -748,6 +751,7 @@
buildActionMask = 2147483647;
files = (
27E40B9226CF533D00A0F634 /* BlockTaskTests.swift in Sources */,
2766A4652706B22300C04DA9 /* ProducerTests.swift in Sources */,
270351C125C2BD26007AF693 /* AttachableTests.swift in Sources */,
27F4F05826E499ED005BAC34 /* ResultBoardTests.swift in Sources */,
27058AE026DA4281008FB4F6 /* BarrierTests.swift in Sources */,
Expand Down
41 changes: 41 additions & 0 deletions Example/Tests/ProducerTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// ProducerTests.swift
// Boardy_Tests
//
// Created by NGUYEN CHI CONG on 10/1/21.
// Copyright © 2021 [iF] Solution. All rights reserved.
//

@testable import Boardy
import XCTest

private class StubBoard: Board, ActivatableBoard {
func activate(withOption option: Any?) {}
}

class ProducerTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testBoxedProducer() throws {
var producer: BoardProducer? = BoardProducer(registrations: [])

let boxedProducer = BoardDynamicProducerBox(producer: producer)
XCTAssertNotNil(boxedProducer.producer)

boxedProducer.registerBoard("add-one") { id in
StubBoard(identifier: id)
}

let regBoard = producer?.produceBoard(identifier: "add-one")
XCTAssertNotNil(regBoard)

producer = nil
XCTAssertNil(boxedProducer.producer)
}
}

0 comments on commit af0073a

Please sign in to comment.