通过属性包装器崩溃的嵌套依赖项注入 [英] Nested dependency injection through Property wrapper crashes

查看:61
本文介绍了通过属性包装器崩溃的嵌套依赖项注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

遵循,一切正常

但是,当我尝试使用相同的方法来解决嵌套的依赖项时(注入依赖项的类又具有依赖项-在我们的例子中是NetworkService),它崩溃了.我在这里做错了什么?任何帮助将不胜感激.

But when I tried the same thing for resolving a nested dependency (Dependency injected class has a dependency in turn - NetworkService In our case), it crashed. What am I doing wrong here? any help would be highly appreciated.

实时场景

class AppContainer {
    static let shared = AppContainer()

    var index: [Any] = [NetworkingLibrary(), NetworkService()]

    func resolve<T>(_ type: T.Type) -> T {
        return index.first(where: { $0 as? T != nil }) as! T
    }
}

@propertyWrapper
struct Inject<Value> {
    var value: Value

    var wrappedValue: Value {
        get {
            return value
        }
        set {
            value = newValue
        }
    }

    init(_ container: AppContainer = AppContainer.shared) {
        value = container.resolve(Value.self)
    }
}

class UserService {
    @Inject() var networkLayer: NetworkLayer

    init() { }

    func fetchUsers() {
        networkLayer.fetchData()
    }
}

class PostService {
    @Inject() var networkLayer: NetworkLayer

    init() { }

    func fetchPosts() {
        networkLayer.fetchData()
    }
}

protocol NetworkLayer {
    func fetchData()
}

class NetworkService: NetworkLayer {
    @Inject() var networkLibrary: NetworkingLibraryProtocol //Expecting networkLibrary to be resolved to NetworkingLibrary()
    func fetchData() {
        networkLibrary.fetch()
        print("Fetching Data")
    }
}


let postService = PostService() // crashes here
postService.fetchPosts()

let userService = UserService() // crashes here
userService.fetchUsers()

您可以在操场上运行的代码

class AppContainer {
    static let shared = AppContainer()

    var index: [Any] = ["StackOverflow", NetworkService()]

    func resolve<T>(_ type: T.Type) -> T {
        return index.first(where: { $0 as? T != nil }) as! T
    }
}

@propertyWrapper
struct Inject<Value> {
    var value: Value

    var wrappedValue: Value {
        get {
            return value
        }
        set {
            value = newValue
        }
    }

    init(_ container: AppContainer = AppContainer.shared) {
        value = container.resolve(Value.self)
    }
}

class UserService {
    @Inject() var networkLayer: NetworkLayer

    init() { }

    func fetchUsers() {
        networkLayer.fetchData()
    }
}

class PostService {
    @Inject() var networkLayer: NetworkLayer

    init() { }

    func fetchPosts() {
        networkLayer.fetchData()
    }
}

protocol NetworkLayer {
    func fetchData()
}

class NetworkService: NetworkLayer {
    @Inject() var str: String // Expecting str to be resolved to "StackOverflow"
    func fetchData() {
        print(str)
        print("Fetching Data")
    }
}


let postService = PostService()
postService.fetchPosts()

let userService = UserService()
userService.fetchUsers()

崩溃日志:-

错误:执行被中断,原因:EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0).该过程已被中断,请使用"thread return -x"返回到表达式求值之前的状态.

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0). The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

推荐答案

我也在使用属性包装程序在Swift 5.1中搜索依赖注入.

I was also searching for Dependency Injection in Swift 5.1 using property wrappers.

这对我有用-与您的解决方案非常相似,并且非常适合嵌套依赖项:

This is what worked for me - it's very similar to your solution and works perfectly for nested dependencies:

enum Dependencies {
    struct Name: Equatable {
        let rawValue: String
        static let `default` = Name(rawValue: "__default__")
        static func == (lhs: Name, rhs: Name) -> Bool { lhs.rawValue == rhs.rawValue }
    }

    final class Container {
        private var dependencies: [(key: Dependencies.Name, value: Any)] = []

        static let `default` = Container()

        func register(_ dependency: Any, for key: Dependencies.Name = .default) {
            dependencies.append((key: key, value: dependency))
        }

        func resolve<T>(_ key: Dependencies.Name = .default) -> T {
            return (dependencies
                .filter { (dependencyTuple) -> Bool in
                    dependencyTuple.key == key
                        && dependencyTuple.value is T
                }
                .first)?.value as! T
        }
    }

    @propertyWrapper
    struct Inject<T> {
        private let dependencyName: Name
        private let container: Container
        var wrappedValue: T { container.resolve(dependencyName) }

        init(_ dependencyName: Name = .default, on container: Container = .default) {
            self.dependencyName = dependencyName
            self.container = container
        }
    }
}

这就是您在代码中使用它的方式:

And this is how you use it in your code:

Dependencies.Container.default.register(NetworkService())
Dependencies.Container.default.register(TransactionRepository())
Dependencies.Container.default.register(TransactionService())

class TransactionService {
    @Dependencies.Inject() private var networkService: NetworkService
    @Dependencies.Inject() private var transactionRepository: TransactionRepository
}

class SomeOtherService {
    @Dependencies.Inject() private var transactionService: TransactionService
}

完整说明可在此处中找到.

这篇关于通过属性包装器崩溃的嵌套依赖项注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆