struct WeakObject<TYPE where TYPE:AnyObject> : Equatable, Hashable
{
weak var _value : TYPE?
let _originalHashValue : Int
init (value: TYPE)
{
_value = value
// We keep around the original hash value so that we can return it to represent this
// object even if the value became Nil out from under us because the object went away.
_originalHashValue = ObjectIdentifier(value).hashValue
}
var value : TYPE?
{
return _value
}
var hashValue: Int
{
return _originalHashValue
}
}
func ==<T>(lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool
{
if lhs.value == nil && rhs.value == nil {
return true
}
else if lhs.value == nil || rhs.value == nil {
return false
}
// If the objects are the same, then we are good to go
return lhs.value! === rhs.value!
}
这里's how to make @GoZoner'的答案很符合 Hashable ,因此它可以在Container对象中编入索引,例如: Set , Dictionary , Array 等 .
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
}
7
基于Kaz Yoshikawa的回答
详情
xCode 9.1,Swift 4
解决方案
WeakObject
import Foundation
protocol WeakObjectProtocol {
associatedtype WeakObjectType
var value: WeakObjectType? {get set}
init(object: WeakObjectType)
}
class WeakObject<T: AnyObject>: WeakObjectProtocol {
typealias WeakObjectType = T
weak var value: WeakObjectType?
required init(object: WeakObjectType) {
self.value = object
}
var referenceCount: Int {
return CFGetRetainCount(value)
}
}
extension WeakObject: Equatable {
static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
return lhs.value === rhs.value
}
}
extension WeakObject: Hashable {
var hashValue: Int {
if var value = value { return UnsafeMutablePointer<T>(&value).hashValue }
return 0
}
}
extension WeakObject: CustomStringConvertible {
var description: String {
if let value = value {
let className = String(describing: type(of: value.self))
return "{class: \(className); referenceCount: \(referenceCount)}"
}
return "nil"
}
}
扩展阵列
import Foundation
extension Array where Element: AnyObject {
var weak: Array<WeakObject<Element>> {
var weakArray = [WeakObject<Element>]()
for item in self {
let obj = WeakObject(object: item)
weakArray.append(obj)
}
return weakArray
}
}
extension Array where Element: WeakObjectProtocol {
typealias EnumeratedWeakObjectClosure = (_ index: Int, _ value: Element.WeakObjectType?)->()
typealias WeakObjectClosure = (_ value: Element.WeakObjectType?)->()
mutating func removeNils() {
self = self.flatMap{ (element) -> Element? in
if element.value == nil {
return nil
}
return element
}
}
mutating func append(weakValue: Element.WeakObjectType) {
append(Element(object: weakValue))
}
subscript(index: Int) -> Element.WeakObjectType? {
get {
return self[index].value
}
}
func `for` (closure: WeakObjectClosure){
for item in self {
closure(item.value)
}
}
func forEnumerated (closure: EnumeratedWeakObjectClosure) {
for (index,item) in self.enumerated() {
closure(index, item.value)
}
}
mutating func remove(index: Int, closure: EnumeratedWeakObjectClosure) {
closure(index, self[index].value)
remove(at: index)
}
mutating func remove(index: Int, closure: WeakObjectClosure) {
closure(self[index].value)
remove(at: index)
}
}
用法
// Array of week objects
var weakArray = [WeakObject<UIView>]()
// Get array of week objects (transfom from [AnyObject])
// way 1
weakArray = view.subviews.weak
// way 2
weakArray = [view.subviews[0], view.subviews[1]].weak
// Add single element to the end of the array
weakArray.append(weakValue: UIView())
// For loop
weakArray.for { (element) in
print("\(String(describing: element))")
}
// For loop with index (position number)
weakArray.forEnumerated { (index, element) in
print("\(index) \(String(describing: element))")
}
class Random {
subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
get {
return rand(min-1, max+1)
}
}
}
let rand = Random()
func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
let _min = min + 1
let difference = max - _min
return T(arc4random_uniform(UInt32(difference))) + _min
}
public struct WeakLabel {
public weak var label : Label?
public init(_ label: Label?) {
self.label = label
}
}
public class Label : UILabel {
static var _allLabels = [WeakLabel]()
public static var allLabels:[WeakLabel] {
get {
_allLabels = _allLabels.filter{$0.label != nil}
return _allLabels.filter{$0.label != nil}.map{$0.label!}
}
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
Label._allLabels.append(WeakLabel(self))
}
public override init(frame: CGRect) {
super.init(frame: frame)
Label._allLabels.append(WeakLabel(self))
}
}
2
针对同一问题的又一个解决方案......这个问题的重点是存储对象的弱引用,但也允许存储结构 .
[我不确定它有多有用,但确实需要一段时间才能使语法正确]
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
15 回答
创建一个通用包装器:
将此类的实例添加到您的数组 .
定义
Weak
时,您可以使用struct
或class
.此外,为了帮助获取数组内容,您可以执行以下操作:
上面的
AnyObject
的使用应该用T
替换 - 但我不认为当前的Swift语言允许扩展定义为这样 .您可以将NSHashTable与weakObjectsHashTable一起使用 .
NSHashTable.weakObjectsHashTable()
对于Swift 3:
NSHashTable.weakObjects()
NSHashTable Class Reference
This is not my solution. I found it on the Apple Developer Forums.
@GoZoner有一个很好的答案,但它崩溃了Swift编译器 .
这是一个弱对象容器的版本不会崩溃当前发布的编译器 .
然后,您可以创建这些容器的数组:
派对有点迟,但试试我的 . 我实现为Set而不是数组 .
WeakObjectSet
用法
请注意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
正如gokeji所提到的,我发现NSString不会根据使用中的代码取消分配 . 我摸不着头脑,按照以下方式写了MyString类 .
然后像这样用
MyString
替换NSString
. 然后奇怪地说它有效 .然后我发现一个奇怪的页面可能与此问题有关 .
https://bugs.swift.org/browse/SR-5511
它说问题是
RESOLVED
,但我想知道这是否仍然与这个问题有关 . 无论如何,MyString或NSString之间的行为差异超出了这个范围,但如果有人想出这个问题,我将不胜感激 .您可以通过创建包装器对象来保存弱指针来完成此操作 .
然后在阵列中使用这些
我有同样的想法用泛型创建弱容器 .
结果我为
NSHashTable
创建了包装器:用法:
这不是最好的解决方案,因为
WeakSet
可以用任何类型初始化,如果这种类型不符合AnyObject
协议,那么应用程序将崩溃,原因很详细 . 但我现在没有看到任何更好的解决方案 .原始解决方案是以这种方式定义
WeakSet
:但在这种情况下
WeakSet
无法使用协议进行初始化:目前上面的代码无法编译(Swift 2.1,Xcode 7.1) .
这就是为什么我放弃符合
AnyObject
并添加额外的警卫fatalError()
断言 .功能样式包装怎么样?
只需调用返回的闭包来检查目标是否仍然存活 .
您可以将此闭包存储到数组中 .
并且您可以通过映射调用闭包来检索弱捕获的值 .
WeakContainer的现有示例很有用,但它并没有真正帮助在现有的swift容器(如Lists和Dictionaries)中使用弱引用 .
如果要使用List等方法,那么WeakContainer将需要实现Equatable . 所以我添加了代码以允许WeakContainer相等 .
如果你想在字典中使用WeakContainer,我也使它可以使用它,因此它可以用作字典键 .
我还将它重命名为WeakObject,强调这仅适用于类类型,并将其与WeakContainer示例区分开来:
这允许你做一些很酷的东西,比如使用弱引用词典:
这里's how to make @GoZoner'的答案很符合
Hashable
,因此它可以在Container对象中编入索引,例如:Set
,Dictionary
,Array
等 .详情
xCode 9.1,Swift 4
解决方案
用法
完整样本
结果
其他答案涵盖了泛型角度 . 以为我会分享一些涵盖
nil
角度的简单代码 .我想要一个当前存在于应用程序中的所有
Label
的静态数组(偶尔读取),但是我不想看到nil
以前的旧数据库 .没什么好看的,这是我的代码......
针对同一问题的又一个解决方案......这个问题的重点是存储对象的弱引用,但也允许存储结构 .
[我不确定它有多有用,但确实需要一段时间才能使语法正确]
你可以在
Array
周围创建包装器 . 或使用此库https://github.com/NickRybalko/WeakPointerArraylet array = WeakPointerArray<AnyObject>()
这是类型安全的 .我基于@Eonil的工作,因为我喜欢闭包弱绑定策略,但我不想使用函数运算符来变量,因为它感觉非常反直觉
相反,我所做的如下:
通过这种方式,您可以执行以下操作:
由于
NSPointerArray
已经自动处理了大部分内容,因此我通过为其设置类型安全包装来解决问题,这避免了其他答案中的许多样板:用法示例:
它预先做的更多,但在其余代码中的使用更加清晰IMO . 如果你想让它更像数组,你甚至可以实现下标,使它成为
SequenceType
等(但我的项目只需要append
和forEach
所以我手头没有确切的代码) .