微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在类型上使用 Property Wrapper 抽象单例?

如何解决如何在类型上使用 Property Wrapper 抽象单例?

在协议中,我想从函数创建一个实例,所以我使用一个容器来存储这样的静态实例:

protocol MyProtocol {
    func networkService() -> NetworkService
}

extension MyProtocol {

    func networkService() -> NetworkService {
        if Singletons.networkService == nil {
            Singletons.networkService = NetworkService(abc: 123)
        }

        return Singletons.networkService!
    }
}

private enum Singletons {
    static var networkService: NetworkService?
}

稍后,类型可以符合它并替换认实现,但也需要单个实例:

struct MyType: MyProtocol {
    private static var networkService: NetworkService?

    func networkService() -> NetworkService {
        if Self.networkService == nil {
            Self.networkService = NetworkService(abc: 555)
        }

        return Self.networkService!
    }
}

我希望通过使用 Property Wrapper 封装这个创建单例的仪式,但在类型上。我想做这样的事情:

protocol MyProtocol {
    func networkService() -> NetworkService
}

extension MyProtocol {

    func networkService() -> NetworkService {
        @Singleton
        NetworkService(abc: 123)
    }
}

////

struct MyType: MyProtocol {

    func networkService() -> NetworkService {
        @Singleton
        NetworkService(abc: 555)
    }
}

有没有办法实现这个或类似的东西?

解决方法

这是我的第一次尝试:

struct Single {
    private static var instances = [String: Any]()

    static func make<T>(_ instance: () -> T) -> T {
        let key = String(describing: type(of: T.self))

        guard let value = instances[key] as? T else {
            let resolved = instance()
            instances[key] = resolved
            return resolved
        }

        return value
    }
}

protocol NetworkService {}
struct NetworkDefaultService: NetworkService {
    let id = UUID().uuidString

    init() {
        print("Network Default: \(id)")
    }
}

struct NetworkMockService: NetworkService {
    let id = UUID().uuidString

    init() {
        print("Network Mock: \(id)")
    }
}

protocol LocationService {}
class LocationDefaultService: LocationService {
    let id = UUID().uuidString

    init() {
        print("Location Default: \(id)")
    }
}

protocol NonSingleService {}
struct NonSingleDefaultService: NonSingleService {
    let id = UUID().uuidString

    init() {
        print("Non-Single Default: \(id)")
    }
}

protocol Context {
    func networkService() -> NetworkService
    func locationService() -> LocationService
    func nonSingleService() -> NonSingleService
}

extension Context {

    func networkService() -> NetworkService {
        Single.make {
            NetworkDefaultService()
        }
    }

    func locationService() -> LocationService {
        Single.make {
            LocationDefaultService()
        }
    }
}

struct AppContext: Context {

    func networkService() -> NetworkService {
        Single.make {
            NetworkMockService()
        }
    }

    func nonSingleService() -> NonSingleService {
        NonSingleDefaultService()
    }
}

let context = AppContext()
context.networkService()
context.networkService()
context.locationService()
context.locationService()
context.nonSingleService()
context.nonSingleService()

打印:

Network Mock: 48CBDE3A-26D2-4767-A6AA-F846F8863A52
Location Default: 4846953B-93F6-4025-A970-DA5B47470652
Non-Single Default: 957979D8-9F3E-428E-BD87-B9F45D56B755
Non-Single Default: 816D2886-D606-4558-A842-295C833AE4C8

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。