我想在Swift中存储一个弱引用数组。数组本身不应该是弱引用——它的元素应该是。我认为Cocoa NSPointerArray提供了一个非类型安全的版本。
当前回答
我有同样的想法来创建带有泛型的弱容器。 因此,我为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()断言添加额外的保护。
其他回答
我有同样的想法来创建带有泛型的弱容器。 因此,我为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()断言添加额外的保护。
创建一个通用包装器,如下:
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时,可以使用struct或class。
同样,为了帮助获取数组内容,你可以做一些如下的事情:
extension Array where Element:Weak<AnyObject> {
mutating func reap () {
self = self.filter { nil != $0.value }
}
}
上面使用的AnyObject应该替换为T -但我不认为当前的Swift语言允许这样定义扩展。
同样的问题还有另一种解决方案……它的重点是存储对对象的弱引用,但也允许存储结构。
[我不确定它有多有用,但它确实花了一段时间来纠正语法]
class WeakWrapper : Equatable {
var valueAny : Any?
weak var value : AnyObject?
init(value: Any) {
if let valueObj = value as? AnyObject {
self.value = valueObj
} else {
self.valueAny = value
}
}
func recall() -> Any? {
if let value = value {
return value
} else if let value = valueAny {
return value
}
return nil
}
}
func ==(lhs: WeakWrapper, rhs: WeakWrapper) -> Bool {
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}
class Stuff {}
var weakArray : [WeakWrapper] = [WeakWrapper(value: Stuff()), WeakWrapper(value: CGRectZero)]
extension Array where Element : WeakWrapper {
mutating func removeObject(object: Element) {
if let index = self.indexOf(object) {
self.removeAtIndex(index)
}
}
mutating func compress() {
for obj in self {
if obj.recall() == nil {
self.removeObject(obj)
}
}
}
}
weakArray[0].recall()
weakArray[1].recall() == nil
weakArray.compress()
weakArray.count
下面是如何使@GoZoner的伟大的答案符合哈希,所以它可以在容器对象中索引:集,字典,数组等。
private class Weak<T: AnyObject>: Hashable {
weak var value : T!
init (value: T) {
self.value = value
}
var hashValue : Int {
// ObjectIdentifier creates a unique hashvalue for objects.
return ObjectIdentifier(self.value).hashValue
}
}
// Need to override so we can conform to Equitable.
private func == <T>(lhs: Weak<T>, rhs: Weak<T>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
在很多情况下,返回一个可取消的选项会更简洁。这允许调用站点决定何时显式地销毁值(以及通过解压缩隐式地销毁值):
public protocol Cancellable {
func cancel()
}
private struct MyValue: Identifiable {
let id: String
// ...
}
private class CancellationHandler: Cancellable {
let handler: () -> ()
init(handler: @escaping () -> ()) { self.handler = handler }
func cancel() { handler() }
deinit { handler() }
}
public class Container {
private var array = [MyType]()
public func add() -> Cancellable {
let value = MyValue(...)
array.append(value)
return CancellationHandler {
array.removeFirst(where: { $0.id == value.id })
}
}
}
let cancellable = container.add()
// Both cancellable.cancel() and the cancellable descoping
// will call the `cancel` function, removing the value from array.
推荐文章
- swift语言中的结构与类
- 我如何在Swift连接字符串?
- 我应该如何从字符串中删除所有的前导空格?- - - - - -斯威夫特
- 新的自动引用计数机制是如何工作的?
- Swift:理解// MARK
- Swift -转换为绝对值
- Swift编译器错误:“框架模块内的非模块化头”
- 从父iOS访问容器视图控制器
- 自定义dealloc和ARC (Objective-C)
- NSRange从Swift Range?
- 我可以使用范围操作符与if语句在Swift?
- 在Swift中转换字符串为日期
- 点击按钮时如何打开手机设置?
- 在Swift中使用自定义消息抛出错误/异常的最简单方法?
- 编译器错误:带有Objective-C选择器的方法与前面带有相同Objective-C选择器的声明冲突