Skip to content

Instantly share code, notes, and snippets.

@eralston
Last active July 5, 2023 09:11
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eralston/8010285 to your computer and use it in GitHub Desktop.
Save eralston/8010285 to your computer and use it in GitHub Desktop.
An pair of Objective-C categories on NSArray and NSMutableArray that provides a mechanism for weak referencing any type of Objective-C object. This was created when I found a case, referencing protocols, where NSPointerArray did not work for my needs.
//
// NSMutableArray+WeakArray.h
//
#import <Foundation/Foundation.h>
///
/// Category on NSArray that provides read methods for weak pointers
/// NOTE: These methods may scan the whole array
///
@interface NSArray(WeakArray)
- (__weak id)weakObjectForIndex:(NSUInteger)index;
-(id<NSFastEnumeration>)weakObjectsEnumerator;
@end
///
/// Category on NSMutableArray that provides write methods for weak pointers
/// NOTE: These methods may scan the whole array
///
@interface NSMutableArray (FRSWeakArray)
-(void)addWeakObject:(id)object;
-(void)removeWeakObject:(id)object;
-(void)cleanWeakObjects;
@end
//
// NSMutableArray+WeakArray.m
//
#import "NSArray+WeakArray.h"
///
/// A wrapper for a weak pointer, meant to allow for arrays of weak references (that don't suck)
///
@interface WAArrayWeakPointer : NSObject
@property (nonatomic, weak) NSObject *object;
@end
@implementation WAArrayWeakPointer
@end
@implementation NSArray (WeakArray)
///
/// Returns the weakly referenced object at the given index
///
-(__weak id)weakObjectForIndex:(NSUInteger)index
{
WAArrayWeakPointer *ptr = [self objectAtIndex:index];
return ptr.object;
}
///
/// Gets the weak pointer for the given object reference
///
-(WAArrayWeakPointer *)weakPointerForObject:(id)object
{
// Linear search for the object in question
for (WAArrayWeakPointer *ptr in self) {
if(ptr) {
if(ptr.object == object) {
return ptr;
}
}
}
return nil;
}
///
/// Returns a fast enumeration collection for all of the weakly referenced objects in this collection
///
-(id<NSFastEnumeration>)weakObjectsEnumerator
{
NSMutableArray *enumerator = [[NSMutableArray alloc] init];
for (WAArrayWeakPointer *ptr in self) {
if(ptr && ptr.object) {
[enumerator addObject:ptr.object];
}
}
return enumerator;
}
@end
@implementation NSMutableArray (FRSWeakArray)
///
/// Adds a weak reference to the given object to the collection
///
-(void)addWeakObject:(id)object
{
if(!object)
return;
WAArrayWeakPointer *ptr = [[WAArrayWeakPointer alloc] init];
ptr.object = object;
[self addObject:ptr];
[self cleanWeakObjects];
}
///
/// Removes a weakly referenced object from the collection
///
-(void)removeWeakObject:(id)object
{
if(!object)
return;
// Find the underlying object in the array
WAArrayWeakPointer *ptr = [self weakPointerForObject:object];
if(ptr) {
[self removeObject:ptr];
[self cleanWeakObjects];
}
}
///
/// Cleans the collection of any lost weak objects
///
-(void)cleanWeakObjects
{
// Build a list of dead references
NSMutableArray *toBeRemoved = [[NSMutableArray alloc] init];
for (WAArrayWeakPointer *ptr in self) {
if(ptr && !ptr.object) {
[toBeRemoved addObject:ptr];
}
}
// Remove the dead references from the collection
for(WAArrayWeakPointer *ptr in toBeRemoved) {
[self removeObject:ptr];
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment