[iOS, Swift] Dependency Injection using ObjectIdentifier

1 minute read

ObjectIdentifier

class Person {
    let name: String

    init(name: String) {
        self.name = name
    }
}

let kim          = Person(name: "kim")
let jeon         = Person(name: "jeon")

let idOfPerson   = ObjectIdentifier(Person.self)
let idOfKim      = ObjectIdentifier(kim)
let idOfJeon     = ObjectIdentifier(jeon)

print("Person Type id: \(idOfPerson)")
print("kim id: \(idOfKim)")
print("jeon id: \(idOfJeon)")

// print
// Person Type id: ObjectIdentifier(0x00000001123f1320)
// kim id: ObjectIdentifier(0x00007f8d9506de10)
// jeon id: ObjectIdentifier(0x00007f8d950a6150)

Dependency Injection using ObjectIdentifier

Example SourceCode

protocol DataSource {
    func fetchData() -> String
}

class NetworkDataSource: DataSource {
    func fetchData() -> String {
        return "a string data from Network API"
    }
}

class Repository {
    private let dataSource: DataSource

    init(dataSource: DataSource) {
        self.dataSource = dataSource
    }

    func fetch() -> String {
        return self.dataSource.fetchData()
    }
}

Dependency Injection

  • Dependency Injection with Register/Resolve Pattern
class DIResolver {
    private var map: [ObjectIdentifier: AnyObject] = [:]

    func register(_ aClass: AnyObject) {
        let id = ObjectIdentifier(type(of: aClass))

        guard map[id] == nil else {
            return
        }

        map[id] = aClass
    }

    func resolve<T>(type: T.Type) -> T? {
        let id = ObjectIdentifier(type)

        return map[id] as? T
    }
}
let dataSourceResolver = DIResolver()

dataSourceResolver.register(NetworkDataSource())

if let dataSource = dataSourceResolver.resolve(type: NetworkDataSource.self) {
    let repository = Repository(dataSource: dataSource)
    print(repository.fetch())
}

for Protocol Type

class DIResolver {
    ...

    func register<T>(_ aClass: T, for protocolType: T.Type) {
        let id = ObjectIdentifier(protocolType)

        guard map[id] == nil,
              let classObject = aClass as? AnyObject else {
            return
        }

        map[id] = classObject
    }

    ...
}
let dataSourceResolver = DIResolver()

dataSourceResolver.register(NetworkDataSource(), for: DataSource.self)

if let dataSource = dataSourceResolver.resolve(type: DataSource.self) {
    let repository = Repository(dataSource: dataSource)
    print(repository.fetch())
}

Reference

Leave a comment