如何在Swift中声明一个弱引用数组?

 手浪用户2702933404 发布于 2023-01-10 11:23

我想在Swift中存储一组弱引用.数组本身不应该是弱引用 - 它的元素应该是.我认为Cocoa NSPointerArray提供了非类型安全版本.

7 个回答
  • 派对有点迟,但试试我的.我实现为Set而不是数组.

    WeakObjectSet

    class WeakObject<T: AnyObject>: Equatable, Hashable {
        weak var object: T?
        init(object: T) {
            self.object = object
        }
    
        var hashValue: Int {
            if let object = self.object { return unsafeAddressOf(object).hashValue }
            else { return 0 }
        }
    }
    
    func == <T> (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.object === rhs.object
    }
    
    
    class WeakObjectSet<T: AnyObject> {
        var objects: Set<WeakObject<T>>
    
        init() {
            self.objects = Set<WeakObject<T>>([])
        }
    
        init(objects: [T]) {
            self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
        }
    
        var allObjects: [T] {
            return objects.flatMap { $0.object }
        }
    
        func contains(object: T) -> Bool {
            return self.objects.contains(WeakObject(object: object))
        }
    
        func addObject(object: T) {
            self.objects.unionInPlace([WeakObject(object: object)])
        }
    
        func addObjects(objects: [T]) {
            self.objects.unionInPlace(objects.map { WeakObject(object: $0) })
        }
    }
    

    用法

    var alice: NSString? = "Alice"
    var bob: NSString? = "Bob"
    var cathline: NSString? = "Cathline"
    
    var persons = WeakObjectSet<NSString>()
    persons.addObject(bob!)
    print(persons.allObjects) // [Bob]
    
    persons.addObject(bob!)
    print(persons.allObjects) // [Bob]
    
    persons.addObjects([alice!, cathline!])
    print(persons.allObjects) // [Alice, Cathline, Bob]
    
    alice = nil
    print(persons.allObjects) // [Cathline, Bob]
    
    bob = nil
    print(persons.allObjects) // [Cathline]
    

    请注意WeakObjectSet不会采用String类型而是采用NSString.因为,String类型不是AnyType.我的快捷版本是Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29).

    代码可以从Gist中获取. https://gist.github.com/codelynx/30d3c42a833321f17d39

    **于2010年11月上市

    我将代码更新为Swift 4

    // Swift 4, Xcode Version 9.1 (9B55)
    
    class WeakObject<T: AnyObject>: Equatable, Hashable {
        weak var object: T?
        init(object: T) {
            self.object = object
        }
    
        var hashValue: Int {
            if var object = object { return UnsafeMutablePointer<T>(&object).hashValue }
            return 0
        }
    
        static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
            return lhs.object === rhs.object
        }
    }
    
    class WeakObjectSet<T: AnyObject> {
        var objects: Set<WeakObject<T>>
    
        init() {
            self.objects = Set<WeakObject<T>>([])
        }
    
        init(objects: [T]) {
            self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
        }
    
        var allObjects: [T] {
            return objects.flatMap { $0.object }
        }
    
        func contains(_ object: T) -> Bool {
            return self.objects.contains(WeakObject(object: object))
        }
    
        func addObject(_ object: T) {
            self.objects.formUnion([WeakObject(object: object)])
        }
    
        func addObjects(_ objects: [T]) {
            self.objects.formUnion(objects.map { WeakObject(object: $0) })
        }
    }
    

    正如gokeji所提到的,我发现NSString不会根据使用中的代码取消分配.我摸不着头脑,按照以下方式写了MyString类.

    // typealias MyString = NSString
    class MyString: CustomStringConvertible {
        var string: String
        init(string: String) {
            self.string = string
        }
        deinit {
            print("relasing: \(string)")
        }
        var description: String {
            return self.string
        }
    }
    

    然后NSStringMyString这样替换.然后奇怪地说它有效.

    var alice: MyString? = MyString(string: "Alice")
    var bob: MyString? = MyString(string: "Bob")
    var cathline: MyString? = MyString(string: "Cathline")
    
    var persons = WeakObjectSet<MyString>()
    
    persons.addObject(bob!)
    print(persons.allObjects) // [Bob]
    
    persons.addObject(bob!)
    print(persons.allObjects) // [Bob]
    
    persons.addObjects([alice!, cathline!])
    print(persons.allObjects) // [Alice, Cathline, Bob]
    
    alice = nil
    print(persons.allObjects) // [Cathline, Bob]
    
    bob = nil
    print(persons.allObjects) // [Cathline]
    

    然后我发现一个奇怪的页面可能与此问题有关.

    弱引用保留解除分配的NSString(仅限XC9 + iOS Sim)

    https://bugs.swift.org/browse/SR-5511

    它说问题是,RESOLVED但我想知道这是否仍然与这个问题有关.无论如何,MyString或NSString之间的行为差​​异超出了这个范围,但如果有人想出这个问题,我将不胜感激.

    2023-01-10 11:24 回答
  • 这不是我的解决方案.我在Apple Developer论坛上找到了它.

    @GoZoner有一个很好的答案,但它崩溃了Swift编译器.

    这是一个弱对象容器的版本不会崩溃当前发布的编译器.

    struct WeakContainer<T where T: AnyObject> {
        weak var _value : T?
    
        init (value: T) {
            _value = value
        }
    
        func get() -> T? {
            return _value
        }
    }
    

    然后,您可以创建这些容器的数组:

    let myArray: Array<WeakContainer<MyClass>> = [myObject1, myObject2]
    

    2023-01-10 11:24 回答
  • 您可以通过创建包装器对象来保存弱指针来完成此操作.

    struct WeakThing<T: AnyObject> {
      weak var value: T?
      init (value: T) {
        self.value = value
      }
    }
    

    然后在阵列中使用这些

    var weakThings = WeakThing<Foo>[]()
    

    2023-01-10 11:24 回答
  • 您可以将NSHashTable与weakObjectsHashTable一起使用. NSHashTable.weakObjectsHashTable()

    对于Swift 3: NSHashTable.weakObjects()

    NSHashTable类参考

    适用于OS X v10.5及更高版本.

    适用于iOS 6.0及更高版本.

    2023-01-10 11:25 回答
  • 功能样式包装怎么样?

    class Class1 {}
    
    func captureWeakly<T> (_ target:T) -> (() -> T?) where T: AnyObject {
        return { [weak target] in
            return target
        }
    }
    
    let obj1 = Class1()
    let obj2 = Class1()
    let obj3 = Class1()
    let captured1 = captureWeakly(obj1)
    let captured2 = captureWeakly(obj2)
    let captured3 = captureWeakly(obj3)
    

    只需调用返回的闭包来检查目标是否仍然存活.

    let isAlive = captured1() != nil
    let theValue = captured1()!
    

    您可以将此闭包存储到数组中.

    let array1 = Array<() -> (Class1?)>([captured1, captured2, captured3])
    

    并且您可以通过映射调用闭包来检索弱捕获的值.

    let values = Array(array1.map({ $0() }))
    

    2023-01-10 11:25 回答
  • 创建一个通用包装器:

    class Weak<T: AnyObject> {
      weak var value : T?
      init (value: T) {
        self.value = value
      }
    }
    

    将此类的实例添加到您的数组.

    class Stuff {}
    var weakly : [Weak<Stuff>] = [Weak(value: Stuff()), Weak(value: Stuff())]
    

    定义时,Weak您可以使用structclass.

    此外,为了帮助获取数组内容,您可以执行以下操作:

    extension Array where Element:Weak<AnyObject> {
      mutating func reap () {
        self = self.filter { nil != $0.value }
      }
    }
    

    AnyObject上面的使用应该替换为T- 但我不认为当前的Swift语言允许扩展定义为这样.

    2023-01-10 11:25 回答
  • 我有同样的想法用泛型创建弱容器.
    结果我创建了包装器NSHashTable:

    class WeakSet<ObjectType>: SequenceType {
    
        var count: Int {
            return weakStorage.count
        }
    
        private let weakStorage = NSHashTable.weakObjectsHashTable()
    
        func addObject(object: ObjectType) {
            guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
            weakStorage.addObject(object as? AnyObject)
        }
    
        func removeObject(object: ObjectType) {
            guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
            weakStorage.removeObject(object as? AnyObject)
        }
    
        func removeAllObjects() {
            weakStorage.removeAllObjects()
        }
    
        func containsObject(object: ObjectType) -> Bool {
            guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
            return weakStorage.containsObject(object as? AnyObject)
        }
    
        func generate() -> AnyGenerator<ObjectType> {
            let enumerator = weakStorage.objectEnumerator()
            return anyGenerator {
                return enumerator.nextObject() as! ObjectType?
            }
        }
    }
    

    用法:

    protocol MyDelegate : AnyObject {
        func doWork()
    }
    
    class MyClass: AnyObject, MyDelegate {
        fun doWork() {
            // Do delegated work.
        }
    }
    
    var delegates = WeakSet<MyDelegate>()
    delegates.addObject(MyClass())
    
    for delegate in delegates {
        delegate.doWork()
    }
    

    它不是最好的解决方案,因为WeakSet可以使用任何类型进行初始化,如果此类型不符合AnyObject协议,则应用程序将因详细原因而崩溃.但我现在没有看到任何更好的解决方案.

    原始解决方案是以WeakSet这种方式定义:

    class WeakSet<ObjectType: AnyObject>: SequenceType {}
    

    但在这种情况下WeakSet无法使用协议初始化:

    protocol MyDelegate : AnyObject {
        func doWork()
    }
    
    let weakSet = WeakSet<MyDelegate>()
    

    目前上面的代码无法编译(Swift 2.1,Xcode 7.1).
    这就是为什么我放弃了符合AnyObject并添加额外的警卫fatalError()断言.

    2023-01-10 11:25 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有