I'd like to store an array of weak references in Swift. The array itself should not be a weak reference - its elements should be. I think Cocoa NSPointerArray
offers a non-typesafe version of this.
-
1What about making a container object that weakly references another object, then making an array of those? (If you don't get a better answer) – nielsbot Jun 09 '14 at 19:37
-
1why don't you use an NSPointerArray ? – Bastian Jun 09 '14 at 19:37
-
@nielsbot That's an old obj-c solution :) To make it Swifty, it should be a generic object! :) However, the real problem is how to get objects removed from the array when the referenced object is deallocated. – Sulthan Jun 09 '14 at 19:40
-
2Right, I'd prefer something with parameterized types. I guess I could make a parameterized wrapper around NSPointerArray, but wanted to see if there were any alternatives. – Bill Jun 09 '14 at 19:52
-
Have you tried `Array
`? – Cy-4AH Jun 09 '14 at 20:01 -
6Just as another option, NSHashTable exists. It's basically an NSSet that allows you to specify how it should reference the objects it contains. – Mick MacCallum Jun 09 '14 at 20:04
-
@Sulthan yes, you will have to use an indirect access... like, if (nil) { remove handle from array } – nielsbot Jun 09 '14 at 20:32
-
This has to be a language bug as all the solutions proposed achieve the immediate result through encapsulation and break the semantics of the type. For example, an array of protocol references lose their protocol identity, meaning that they cannot be exposed to Interface Builder via IBOutlet. – Chris Conover Mar 13 '15 at 20:34
18 Answers
Create a generic wrapper as:
class Weak<T: AnyObject> {
weak var value : T?
init (value: T) {
self.value = value
}
}
Add instances of this class to your array.
class Stuff {}
var weakly : [Weak<Stuff>] = [Weak(value: Stuff()), Weak(value: Stuff())]
When defining Weak
you can use either struct
or class
.
Also, to help with reaping array contents, you could do something along the lines of:
extension Array where Element:Weak<AnyObject> {
mutating func reap () {
self = self.filter { nil != $0.value }
}
}
The use of AnyObject
above should be replaced with T
- but I don't think the current Swift language allows an extension defined as such.

- 67,920
- 20
- 95
- 145
-
18How do you remove the wrapper objects from the array when their value is deallocated? – Sulthan Jun 09 '14 at 20:09
-
I actually just hit on this same idea. Unfortunately, it seems to crash the compiler. I can only get it to work if I eliminate the generic parameter. I'll investigate more and then perhaps submit a bug. – Bill Jun 09 '14 at 20:09
-
10
-
In my experience, it's trivial to crash the compiler when you start using weak vars. – Bill Jun 09 '14 at 20:11
-
@Sulthan you don't. They just hang around. You'd check for a 'reclaimed value' with `if let value = array[index].value? { ... }`. Or define `class WeakArray : Array { ... }` – GoZoner Jun 09 '14 at 20:13
-
2
-
1@GoZoner I'm going to award you the accepted answer, because I think this is the correct solution and the compiler has simply not caught up. :-) – Bill Jun 09 '14 at 20:19
-
This is correct. It only crashes in Playground but works fine in a normal project – John Estropia Jun 10 '14 at 04:44
-
In my Swift project (i.e. not a playground) in Xcode 6.1.1, adding this code crashes the compiler ("Segmentation Fault 11"). It doesn't crash when I create a new project though, so... dunno. Just keep in mind that this may cause Xcode to act up. – jasamer Dec 16 '14 at 13:07
-
It doesn't work. The controller is still not deinitialised because of this. – Bartłomiej Semańczyk Jul 29 '15 at 20:30
-
6Please post your problem code in a new question; no reason to ding my answer when it *might* be your code! – GoZoner Jul 30 '15 at 00:35
-
1In Xcode 7.2.1 / Swift 2 this causes a compiler error: Using as a concrete type conforming to protocol AnyObject is not supported. – Brian Stewart Feb 19 '16 at 15:41
-
More info please. In a 7.2.1 Playground, the provided code compiles/executes as expected. – GoZoner Feb 19 '16 at 16:11
-
2@EdGamble The provided code works as it is, but fails if you replace the class `Stuff` by a protocol; see [this related question](http://stackoverflow.com/q/32807948/1821701) – Theo Apr 28 '16 at 12:03
-
Weak-ness only really applies to reference types - hence `AnyObject` or `:class` types. You can observe this trying to declare `weak var value :
` with different types - the Swift compiler will limit your choices to 'class types'. – GoZoner Apr 28 '16 at 14:10 -
1
-
2A struct would be better, as it would be kept on the stack instead of needing a heap fetch. – KPM Feb 21 '18 at 09:49
You can use the NSHashTable with weakObjectsHashTable. NSHashTable<ObjectType>.weakObjectsHashTable()
For Swift 3: NSHashTable<ObjectType>.weakObjects()
Available in OS X v10.5 and later.
Available in iOS 6.0 and later.
-
-
2This is clever, but like GoZoner's answer, this doesn't work with types that are `Any` but not `AnyObject`, such as protocols. – Aaron Brager Jan 21 '16 at 20:23
-
@SteveWilford But a protocol can be implemented by a class, which would make it a reference type – Aaron Brager Jul 08 '16 at 02:04
-
4a protocol can extend class and then you can use it as weak (e.g. protocol MyProtocol: class) – Yasmin Tiomkin Sep 24 '16 at 14:31
-
8I get a compiler error with `MyProtocol: class` and `NSHashTable
.weakObjects()`. "'NSHashTable' requires that 'MyProtocol' be a class type. – Greg Oct 24 '18 at 16:35 -
1Only thing to consider: the `.count` method for `NSHashTable` has a few issues with caching, such that making an object nil, and immediately calling `count` gives you the wrong value. Generally not a problem in the codebase, but unit tests do fail as a result. – XmasRights Oct 16 '19 at 09:14
-
Also make sure order doesn't matter. NSHashTable doesn't maintain order of its elements. – KellyHuberty Apr 10 '21 at 22:01
A functional programming approach
No extra class needed.
Simply define an array of closures () -> Foo?
and capture the foo instance as weak using [weak foo]
.
let foo = Foo()
var foos = [() -> Foo?]()
foos.append({ [weak foo] in return foo })
foos.forEach { $0()?.doSomething() }

- 5,087
- 3
- 26
- 29
-
Very nice. I think you lose compactMap and would need `filter { $0() != nil }` – MH175 May 18 '21 at 00:48
-
2If you wanted more convenient/descriptive syntax you can also declare a typealias `WeakArray
= [() -> T?]` – MH175 May 18 '21 at 00:56
It's kind of late for party, but try mine. I implemented as a Set not an Array.
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) })
}
}
Usage
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]
Beware that WeakObjectSet won't take String type but NSString. Because, String type is not an AnyType. My swift version is Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
.
Code can be grabbed from Gist. https://gist.github.com/codelynx/30d3c42a833321f17d39
** ADDED IN NOV.2017
I updated the code to 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) })
}
}
As gokeji mentioned, I figured out NSString won't get deallocated based on the code in usage. I scratched my head and I wrote MyString class as follows.
// 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
}
}
Then replace NSString
with MyString
like this. Then strange to say it works.
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]
Then I found a strange page may be related to this issue.
Weak reference retains deallocated NSString (XC9 + iOS Sim only)
https://bugs.swift.org/browse/SR-5511
It says the issue is RESOLVED
but I am wondering if this is still related to this issue.
Anyway, Behavior differences between MyString or NSString are beyond this context, but I would appreciate if someone figured this issue out.

- 1,577
- 1
- 18
- 26
-
I've adopted this solution for my project. Great job! Just one suggestion, this solution doesn't seem to remove `nil` values from the internal `Set`. So I've added a `reap()` function mentioned in the top answer, and made sure to call `reap()` every time the `WeakObjectSet` is accessed. – gokeji Nov 13 '17 at 21:39
-
Hmm wait, for some reason this doesn't work in Swift 4/iOS 11. Seems like the weak reference doesn't get deallocated right away when the value becomes `nil` anymore – gokeji Nov 13 '17 at 23:33
-
1I updated code to Swift4, see the second half of the answer. I seems NSString has some deallocation issues, but It should still work on your custom class objects. – Kaz Yoshikawa Nov 14 '17 at 05:39
-
Thanks so much for looking into it @KazYoshikawa, and updating the answer! I also realized later that a custom class works, whereas `NSString` doesn't. – gokeji Nov 14 '17 at 19:17
-
Thank you so much for this answer. I tried to use this and after running the memory leak instrument, I see some leaks that come from the `WeakObjectSet class`. The way I use it is I have weak references to UIKit components such as `UITableViews`, `UICollectionViews`. These components implement a class protocol `A`, and then in my class I declare a weak set like this: `var set = WeakObjectSet()`. When the ViewController dismisses along with its views, `set` behaves correctly (the views are gone from the set) but the memory instrument shows a leak at `specialized WeakObject.init(object:)`. – Guy Daher Dec 18 '17 at 16:34
-
2I've made the experience that the pointer that is returned by `UnsafeMutablePointer
(&object)` can change randomly (same with `withUnsafePointer`). I now use a version backed by a `NSHashTable`: https://gist.github.com/simonseyer/cf73e733355501405982042f760d2a7d. – simonseyer Feb 27 '18 at 15:42 -
@simonseyer Please add this as an answer describing why you made it and how to use it; I'll vote for it! – meaning-matters Dec 07 '19 at 10:30
-
@meaning-matters I guess you can just upvote this reply https://stackoverflow.com/a/27108747. My code only provides a very thing wrapper around NSHashTable. You could even argue that just using it directly is better because it doesn't shadow what is used underneath. – simonseyer Dec 08 '19 at 14:00
-
I realized that `hashValue` will change its value after deallocation. I updated WeakObjectSet code for recent Xcode and Swift. WeakObjectSet.swift - Swift 5 https://gist.github.com/codelynx/73919293f4166edd767f77a4cd178274 – Kaz Yoshikawa Dec 25 '19 at 07:48
-
-
`let subs = persons.allobjects.filter { $0 !== subscriber } persons = WeakObjectSet
() persons?.addObjects(subs)` – Dan Selig Mar 14 '20 at 17:11 -
There are some removing methods if you are referring following gist. https://gist.github.com/codelynx/73919293f4166edd767f77a4cd178274 – Kaz Yoshikawa Mar 14 '20 at 21:46
This is not my solution. I found it on the Apple Developer Forums.
@GoZoner has a good answer, but it crashes the Swift compiler.
Here's a version of a weak-object container doesn't crash the current released compiler.
struct WeakContainer<T where T: AnyObject> {
weak var _value : T?
init (value: T) {
_value = value
}
func get() -> T? {
return _value
}
}
You can then create an array of these containers:
let myArray: Array<WeakContainer<MyClass>> = [myObject1, myObject2]

- 3,138
- 5
- 27
- 33
-
1strange, but doesn't work with structs anymore. Says `EXC_BAD_ACCESS` for me. With class works just fine – mente Jan 09 '15 at 23:34
-
7Structs are value types, it shouldn't work with them. The fact that it crashed at runtime rather than being a compile-time error is a compiler bug. – David Goodine Jul 12 '16 at 17:45
How about functional style wrapper?
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)
Just call returned closure to check the target is still alive.
let isAlive = captured1() != nil
let theValue = captured1()!
And you can store this closures into an array.
let array1 = Array<() -> (Class1?)>([captured1, captured2, captured3])
And you can retrieve the weakly captured values by mapping calling the closures.
let values = Array(array1.map({ $0() }))
Actually, you don't need a function to make a closure. Just capture an object directly.
let captured3 = { [weak obj3] in return obj3 }

- 83,476
- 81
- 317
- 516
-
3
-
With this solution, you can even create an array with multiple values like `var array: [(x: Int, y: () -> T?)]`. Exactly, what I was looking for. – jboi Sep 23 '16 at 09:11
-
1
-
I _loved_ this approach, and I think it's super clever. I made a class implementation using this strategy. Thank you! – Ale Ravasio Aug 16 '18 at 21:38
-
Not too sure about the `let values = Array(array1.map({ $0() })) part`. Since this is no longer an array of closures with weak references, values will be retained until this array is deallocated. If I am correct then it is important to note that you should never retain this array like `self.items = Array(array1.map({ $0() }))` as this beats the purpose. – Matic Oblak Jun 12 '20 at 08:57
You can do this by creating a wrapper object to hold a weak pointer.
struct WeakThing<T: AnyObject> {
weak var value: T?
init (value: T) {
self.value = value
}
}
And then using these in the array
var weakThings = WeakThing<Foo>[]()

- 28,598
- 2
- 97
- 90
-
-
3Says who? The code above works fine for me. The only requirement is that the object becoming weak needs to be a class, not the object holding the weak reference – Joshua Weinberg Jun 09 '14 at 20:13
-
Sorry. I could have sworn I just got a compiler message that said "Cannot use weak variables in structs". You're correct - that compiles. – Bill Jun 09 '14 at 20:15
-
5
-
@onmyway133 AFAIK if protocol is declared to be implemented only by classes it would work. `protocol Protocol : class { ... }` – olejnjak Apr 20 '16 at 11:00
-
@onmyway133 It should work if `Foo` is a protocol. If you use Swift 2, a bug leads to compiler errors for some protocols, however. See [this question](http://stackoverflow.com/q/32807948/1821701) for details and a workaround. – Theo Apr 28 '16 at 12:08
-
@Bill sometimes Xcode errors pop up briefly, then disappear and actually compile fine even with the red mark. (This happened to me as recently as yesterday) – quantumpotato Dec 30 '17 at 17:25
Details
- Swift 5.1, Xcode 11.3.1
Solution
struct WeakObject<Object: AnyObject> { weak var object: Object? }
Option 1
@propertyWrapper
struct WeakElements<Collect, Element> where Collect: RangeReplaceableCollection, Collect.Element == Optional<Element>, Element: AnyObject {
private var weakObjects = [WeakObject<Element>]()
init(wrappedValue value: Collect) { save(collection: value) }
private mutating func save(collection: Collect) {
weakObjects = collection.map { WeakObject(object: $0) }
}
var wrappedValue: Collect {
get { Collect(weakObjects.map { $0.object }) }
set (newValues) { save(collection: newValues) }
}
}
Option 1 usage
class Class1 { // or struct
@WeakElements var weakObjectsArray = [UIView?]() // Use like regular array. With any objects
func test() {
weakObjectsArray.append(UIView())
weakObjectsArray.forEach { print($0) }
}
}
Option 2
struct WeakObjectsArray<Object> where Object: AnyObject {
private var weakObjects = [WeakObject<Object>]()
}
extension WeakObjectsArray {
typealias SubSequence = WeakObjectsArray<Object>
typealias Element = Optional<Object>
typealias Index = Int
var startIndex: Index { weakObjects.startIndex }
var endIndex: Index { weakObjects.endIndex }
func index(after i: Index) -> Index { weakObjects.index(after: i) }
subscript(position: Index) -> Element {
get { weakObjects[position].object }
set (newValue) { weakObjects[position] = WeakObject(object: newValue) }
}
var count: Int { return weakObjects.count }
var isEmpty: Bool { return weakObjects.isEmpty }
}
extension WeakObjectsArray: RangeReplaceableCollection {
mutating func replaceSubrange<C : Collection>( _ subrange: Range<Index>, with newElements: C) where Element == C.Element {
weakObjects.replaceSubrange(subrange, with: newElements.map { WeakObject(object: $0) })
}
}
Option 2 usage
class Class2 { // or struct
var weakObjectsArray = WeakObjectsArray<UIView>() // Use like regular array. With any objects
func test() {
weakObjectsArray.append(UIView())
weakObjectsArray.forEach { print($0) }
}
}
Full sample
do not forget to paste solution code
import UIKit
class ViewController: UIViewController {
@WeakElements var weakObjectsArray = [UIView?]()
//var weakObjectsArray = WeakObjectsArray<UIView>()
override func viewDidLoad() {
super.viewDidLoad()
addSubviews()
}
private func printArray(title: String) {
DispatchQueue.main.async {
print("=============================\n\(title)\ncount: \(self.weakObjectsArray.count)")
self.weakObjectsArray.enumerated().forEach { print("\($0) \(String(describing: $1))") }
}
}
}
extension ViewController {
private func createRandomRectangleAndAdd(to parentView: UIView) -> UIView {
let view = UIView(frame: CGRect(x: Int.random(in: 0...200),
y: Int.random(in: 60...200),
width: Int.random(in: 0...200),
height: Int.random(in: 0...200)))
let color = UIColor(red: CGFloat.random(in: 0...255)/255,
green: CGFloat.random(in: 0...255)/255,
blue: CGFloat.random(in: 0...255)/255,
alpha: 1)
view.backgroundColor = color
parentView.addSubview(view)
return view
}
private func addSubviews() {
(0...1).forEach { _ in addView() }
addButtons()
}
private func createButton(title: String, frame: CGRect, action: Selector) -> UIButton {
let button = UIButton(frame: frame)
button.setTitle(title, for: .normal)
button.addTarget(self, action: action, for: .touchUpInside)
button.setTitleColor(.blue, for: .normal)
return button
}
private func addButtons() {
view.addSubview(createButton(title: "Add",
frame: CGRect(x: 10, y: 20, width: 40, height: 40),
action: #selector(addView)))
view.addSubview(createButton(title: "Delete",
frame: CGRect(x: 60, y: 20, width: 60, height: 40),
action: #selector(deleteView)))
view.addSubview(createButton(title: "Remove nils",
frame: CGRect(x: 120, y: 20, width: 100, height: 40),
action: #selector(removeNils)))
}
@objc func deleteView() {
view.subviews.first { view -> Bool in return !(view is UIButton) }?
.removeFromSuperview()
printArray(title: "First view deleted")
}
@objc func addView() {
weakObjectsArray.append(createRandomRectangleAndAdd(to: view))
printArray(title: "View addded")
}
@objc func removeNils() {
weakObjectsArray = weakObjectsArray.filter { $0 != nil }
printArray(title: "Remove all nil elements in weakArray")
}
}

- 24,482
- 9
- 132
- 127
-
My problem with both options (and many other) is that these types of array are not usable with protocols. For instance this will not compile: `protocol TP: class { } class TC { var a = WeakArray
() var b = WeakObjectsArray – Matic Oblak Jun 12 '20 at 09:01() }` -
@MaticOblak what about using generics? `protocol TP: class { } class TC
where TYPE: TP { var a = WeakObjectsArray – Vasily Bodnarchuk Jun 12 '20 at 13:56() // Use like regular array. With any objects var weakObjectsArray = [TYPE?]() }` -
The idea is that this array can hold objects of different types which implement the same class protocol. By using a generic you lock it down to a single type. For instance imagine having a singleton that holds such array as `delegates`. Then you would have some number of view controllers that would like to use this functionality. You would expect to call `MyManager.delegates.append(self)`. But if `MyManager` is locked to some generic type then this is not very usable. – Matic Oblak Jun 15 '20 at 06:50
-
@MaticOblak ok. Try this: `protocol TP: class { } class MyManager { typealias Delegate = AnyObject & TP static var delegates = [Delegate?]() } class A: TP { } class B: TP { } //MyManager.delegates.append(A()) //MyManager.delegates.append(B())` – Vasily Bodnarchuk Jun 15 '20 at 20:00
-
You now lost the generic part with the array which is a bit important :) I have a feeling that this is just not doable. A limitation of Swift for now... – Matic Oblak Jun 16 '20 at 05:48
-
@MaticOblak why? Look at last sample. I added objects of different classes to MyManager.delegates. I thought you were trying to reach this, no? also you can use type `Any & TP` if needed. – Vasily Bodnarchuk Jun 16 '20 at 11:34
-
Different classes corresponding to same protocol, yes. But to have a such array that it would be defined as generic. So that another manager could use the same tool with another protocol. So the idea is to have a container (an array) of weak objects corresponding to protocol defined through a generic. – Matic Oblak Jun 16 '20 at 11:40
I had the same idea to create weak container with generics.
As result I created wrapper for 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?
}
}
}
Usage:
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()
}
It's not the best solution, because WeakSet
can be initialized with any type, and if this type doesn't conform to AnyObject
protocol then app will crash with detailed reason. But I don't see any better solution right now.
Original solution was to define WeakSet
in this way:
class WeakSet<ObjectType: AnyObject>: SequenceType {}
But in this case WeakSet
can't be initialized with protocol:
protocol MyDelegate : AnyObject {
func doWork()
}
let weakSet = WeakSet<MyDelegate>()
Currently above code can't be compiled (Swift 2.1, Xcode 7.1).
That's why I dropped conforming to AnyObject
and added additional guards with fatalError()
assertions.

- 13,184
- 4
- 41
- 57
Since NSPointerArray
already handles most of this automatically, I solved the problem by making a type-safe wrapper for it, which avoids a lot of the boilerplate in other answers:
class WeakArray<T: AnyObject> {
private let pointers = NSPointerArray.weakObjects()
init (_ elements: T...) {
elements.forEach{self.pointers.addPointer(Unmanaged.passUnretained($0).toOpaque())}
}
func get (_ index: Int) -> T? {
if index < self.pointers.count, let pointer = self.pointers.pointer(at: index) {
return Unmanaged<T>.fromOpaque(pointer).takeUnretainedValue()
} else {
return nil
}
}
func append (_ element: T) {
self.pointers.addPointer(Unmanaged.passUnretained(element).toOpaque())
}
func forEach (_ callback: (T) -> ()) {
for i in 0..<self.pointers.count {
if let element = self.get(i) {
callback(element)
}
}
}
// implement other functionality as needed
}
Example usage:
class Foo {}
var foo: Foo? = Foo()
let array = WeakArray(foo!)
print(array.get(0)) // Optional(Foo)
foo = nil
DispatchQueue.main.async{print(array.get(0))} // nil
It's more work up front, but the usage in the rest of your code is much cleaner IMO. If you want to make it more array-like, you can even implement subscripting, make it a SequenceType
, etc. (but my project only needs append
and forEach
so I don't have the exact code on hand).

- 2,289
- 2
- 11
- 17

- 6,739
- 9
- 52
- 68
-
1
-
That's odd, it's correct in my actual code so I have no idea how that error got into the answer. – John Montgomery Aug 24 '21 at 23:10
The existing example of the WeakContainer is helpful, but it doesn't really help one use weak references in existing swift containers such as Lists and Dictionaries.
If you want to use List methods such as contains, then the WeakContainer will need to implement Equatable. So I added the code to allow the WeakContainer to be equatable.
In case you wanted to use the WeakContainer in dictionaries, I also made it hashable so it can be used as dictionary keys.
I also renamed it to WeakObject to stress that this is only for class types and to differentiate it from the WeakContainer examples:
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!
}
This allows you to do some cool stuff like use a Dictionary of weak references:
private var m_observerDict : Dictionary<WeakObject<AnyObject>,FLObservationBlock> = Dictionary()
func addObserver( observer:AnyObject, block:FLObservationBlock )
{
let weakObserver = WeakObject(value:observer)
m_observerDict[weakObserver] = block
}
func removeObserver( observer:AnyObject )
{
let weakObserver = WeakObject(value:observer)
m_observerDict.removeValueForKey(weakObserver)
}

- 3,691
- 4
- 30
- 32
Here's how to make @GoZoner's great answer conform to Hashable
, so it can be indexed in Container objects like: Set
, Dictionary
, Array
, etc.
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,252
- 7
- 52
- 69
You could create wrapper around Array
. Or use this library https://github.com/NickRybalko/WeakPointerArray
let array = WeakPointerArray<AnyObject>()
It is type safe.

- 202
- 2
- 5
This is a type safe collection that holds containers of weak objects. It also auto removes nil the containers/wrappers when it's accessed.
Example:
protocol SomeDelegate: class {
func doSomething()
}
class SomeViewController: UIViewController {
var delegates: WeakCollection<SomeDelegate> = []
func someFunction(delegate: SomeDelegate) {
delegates.append(delegate)
}
func runDelegates() {
delegates.forEach { $0.doSomething() }
}
}
The custom collection https://gist.github.com/djk12587/46d85017fb3fad6946046925f36cefdc
import Foundation
/**
Creates an array of weak reference objects.
- Important:
Because this is an array of weak objects, the objects in the array can be removed at any time.
The collection itself will handle removing nil objects (garbage collection) via the private function cleanUpNilContainers()
*/
class WeakCollection<T>: RangeReplaceableCollection, ExpressibleByArrayLiteral {
typealias Index = Int
typealias Element = T
typealias Iterator = IndexingIterator<[Element]>
private var weakContainers: [WeakReferenceContainer]
required convenience init(arrayLiteral: Element...) {
self.init()
self.weakContainers = WeakCollection.createWeakContainers(from: arrayLiteral)
}
required init() {
weakContainers = []
}
required init<S>(_ elements: S) where S: Sequence, WeakCollection.Element == S.Element {
self.weakContainers = WeakCollection.createWeakContainers(from: elements)
}
static private func createWeakContainers<S>(from weakCollection: S) -> [WeakReferenceContainer] where S: Sequence,
WeakCollection.Element == S.Element {
return weakCollection.compactMap { WeakReferenceContainer(value: $0 as AnyObject) }
}
func append<S>(contentsOf newElements: S) where S: Sequence, WeakCollection.Element == S.Element {
self.weakContainers.append(contentsOf: WeakCollection.createWeakContainers(from: newElements))
}
var startIndex: Index {
return references.startIndex
}
var endIndex: Index {
return references.endIndex
}
func replaceSubrange<C, R>(_ subrange: R, with newElements: C) where
C: Collection, R: RangeExpression, WeakCollection.Element == C.Element, WeakCollection.Index == R.Bound {
weakContainers.replaceSubrange(subrange, with: WeakCollection.createWeakContainers(from: newElements))
}
func index(after i: Int) -> Int {
return references.index(after: i)
}
func makeIterator() -> IndexingIterator<[Element]> {
return references.makeIterator()
}
subscript(index: Int) -> Element {
get {
return references[index]
}
set {
weakContainers[index] = WeakReferenceContainer(value: newValue as AnyObject)
}
}
}
extension WeakCollection {
private class WeakReferenceContainer {
private(set) weak var value: AnyObject?
init(value: AnyObject?) {
self.value = value
}
}
private func cleanUpNilContainers() {
weakContainers = weakContainers.compactMap { $0.value == nil ? nil : $0 }
}
private var references: [Element] {
cleanUpNilContainers()
return weakContainers.compactMap { $0.value as? T }
}
}

- 191
- 1
- 7
In many cases it is more clean to return a cancellable. This allows the call-site to decide when to destroy the value explicitly (as well as implicitly by descoping):
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.

- 7,816
- 2
- 32
- 40
Other answers have covered the generics angle. Thought I'd share some simple code covering the nil
angle.
I wanted a static array (read occasionally) of all the Label
s that currently exist in the app, but didn't want to see nil
's where the old ones used to be.
Nothing fancy, this is my code...
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))
}
}

- 791
- 7
- 7
-
What about using ```flatMap``` instead of ```filter``` & ```map``` ? – Lukáš Kubánek Nov 30 '15 at 11:06
Yet another solution to the same problem... the focus of this one is on storing a weak reference to an object but allowing you to store a struct too.
[I'm not sure how useful it is, but it did take a while to get the syntax right]
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

- 68,471
- 58
- 283
- 421
I based this on @Eonil 's work, since I loved the closure weak-bind strategy, but I did not want to use a function operator for a variable, since it felt extremely counter intuitive
What I did, instead, is as follows:
class Weak<T> where T: AnyObject {
fileprivate var storedWeakReference: ()->T? = { return nil }
var value: T? {
get {
return storedWeakReference()
}
}
init(_ object: T) {
self.storedWeakReference = storeWeakReference(object)
}
fileprivate func storeWeakReference<T> (_ target:T) -> ()->T? where T: AnyObject {
return { [weak target] in
return target
}
}
}
This way you can do something such as:
var a: UIViewController? = UIViewController()
let b = Weak(a)
print(a) //prints Optional(<UIViewController: 0xSomeAddress>)
print(b.value) //prints Optional(<UIViewController: 0xSomeAddress>)
a = nil
print(a) //prints nil
print(b.value) //prints nil

- 98
- 12