RIBs/Classes/DI/Component.swift (24 lines of code) (raw):
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// The base class for all components.
///
/// A component defines private properties a RIB provides to its internal `Router`, `Interactor`, `Presenter` and
/// view units, as well as public properties to its child RIBs.
///
/// A component subclass implementation should conform to child 'Dependency' protocols, defined by all of its immediate
/// children.
open class Component<DependencyType>: Dependency {
/// The dependency of this `Component`.
public let dependency: DependencyType
/// Initializer.
///
/// - parameter dependency: The dependency of this `Component`, usually provided by the parent `Component`.
public init(dependency: DependencyType) {
self.dependency = dependency
}
/// Used to create a shared dependency in your `Component` sub-class. Shared dependencies are retained and reused
/// by the component. Each dependent asking for this dependency will receive the same instance while the component
/// is alive.
///
/// - note: Any shared dependency's constructor may not switch threads as this might cause a deadlock.
///
/// - parameter factory: The closure to construct the dependency.
/// - returns: The instance.
public final func shared<T>(__function: String = #function, _ factory: () -> T) -> T {
lock.lock()
defer {
lock.unlock()
}
// Additional nil coalescing is needed to mitigate a Swift bug appearing in Xcode 10.
// see https://bugs.swift.org/browse/SR-8704.
// Without this measure, calling `shared` from a function that returns an optional type
// will always pass the check below and return nil if the instance is not initialized.
if let instance = (sharedInstances[__function] as? T?) ?? nil {
return instance
}
let instance = factory()
sharedInstances[__function] = instance
return instance
}
// MARK: - Private
private var sharedInstances = [String: Any]()
private let lock = NSRecursiveLock()
}
/// The special empty component.
open class EmptyComponent: EmptyDependency {
/// Initializer.
public init() {}
}