代码之家  ›  专栏  ›  技术社区  ›  Michael Long

Swift中等级一致性的铸造和测试[副本]

  •  0
  • Michael Long  · 技术社区  · 2 年前

    所以我有了一个新的依赖注入框架, Factory .

    Factory允许作用域实例,基本上允许您在创建服务后缓存它们。其中一个范围是 共享 . 只要外界有人保持对它的强引用,共享的任何实例都将被缓存并返回。在最后一次引用释放对象后,缓存释放对象,并在下一次解析时创建一个新实例。

    显然,这是通过简单地维护对所创建对象的弱引用来实现的。如果弱引用为零,则是创建新对象的时候了。

    这就是问题所在

    弱引用只能应用于引用类型。

    工厂在内部使用泛型来管理类型信息。但我可以创建任何类型的工厂:类、结构、字符串等等。)

    作用域在内部使用装箱类型的字典。如果缓存和框中存在实例,则返回该实例。所以我想 喜欢 要做的就是创建这个。。。

    private struct WeakBox<T:AnyObject>: AnyBox {
        weak var boxed: T
    }
    

    需要AnyObject一致性以允许弱。否则会出现编译器错误。现在我想用这样的东西在我的共享范围内装箱并缓存一个对象。。。

    func cache<T>(id: Int, instance: T) {
        cache[id] = WeakBox(boxed: instance)
    }
    

    但是 也给出了一个编译器错误。(泛型结构WeakBox要求T是类类型。)

    func cache<T>(id: Int, instance: T) {
        if let instance = instance as? AnyObject {
            cache[id] = WeakBox(boxed: instance)
        }
    }
    

    我很乐意回答以下问题,但同样的问题。您不能测试类的一致性,也不能有条件地强制转换到任何对象。同样,它总是成功的。

    private struct WeakBox: AnyBox {
        weak var boxed: AnyObject?
    }
    func cache<T>(id: Int, instance: T) {
        if let instance = instance as? AnyObject {
            cache[id] = WeakBox(boxed: instance)
        }
    }
    

    我现在正在做的是。。。

    private struct WeakBox: AnyBox {
        weak var boxed: AnyObject?
    }
    func cache<T>(id: Int, instance: T) {
        cache[id] = WeakBox(boxed: instance as AnyObject)
    }
    

    哪一个有效,但那一个 instance as AnyObject

    无法在运行时测试类的一致性让我发疯,这似乎是该语言中的一个半重大漏洞。

    你不能测试一致性,也不能强制转换一致性。

    那你能做什么?

    1 回复  |  直到 2 年前
        1
  •  1
  •   Itai Ferber    2 年前

    正如Martin在评论中指出的那样,任何价值都可以转换为 AnyObject 在Swift中,因为Swift将值类型包装在不透明的 _SwiftValue 上课,演员们就会永远成功。不过,这是有办法的。

    检查一个值是否为引用类型(没有这种隐式转换)的方法是检查其是否为 类型 is AnyObject.Type ,如下所示:

    func printIsObject<T>(_: T) {
        if T.self is AnyObject.Type {
            print("Object")
        } else {
            print("Other")
        }
    }
    
    class Foo {}
    struct Bar {}
    enum Quux { case q }
    
    printIsObject(Foo()) // => Object
    printIsObject(Bar()) // => Other
    printIsObject(Quux.q) // => Other
    

    请注意,检查类型是否正确至关重要 是任意对象。类型 is AnyObject . T.self ,表示值类型的对象本身就是一个对象,因此 是AnyObject 将永远成功。相反 是任意对象。类型 询问“这是否继承自 元类型 在所有对象中”,即“表示类型的该对象是否继承自表示所有对象类型的对象?"


    编辑: 显然,我忘了斯威夫特包括 AnyClass 作为的同义词 AnyObject.Type ,因此检查可以简化为 is AnyClass . 然而,将上述内容作为对其工作原理的略微扩展的解释。


    要将其集成到缓存机制中,您需要检查传入的泛型类型,看看它是否 是任意对象。类型 ,并且只有在 已经 一个物体,投射到 任何对象 要存储在弱盒中:

    func cache<T>(id: Int, instance: T) {
        if T.self is AnyObject.Type {
            cache[id] = WeakBox(boxed: instance as AnyObject)
        } else {
            // Store in a different cache, or do whatever.
        }
    }