Skip to content

Instantly share code, notes, and snippets.

@gamenerds
Last active September 17, 2019 12:49
Show Gist options
  • Save gamenerds/62e7a13b786dcb807507 to your computer and use it in GitHub Desktop.
Save gamenerds/62e7a13b786dcb807507 to your computer and use it in GitHub Desktop.
A category to abstract the details of NSPointerArray
#import <Foundation/Foundation.h>
// This helps deal with NSPointerArray that stores pointers to objects that inherit from NSObject.
// Not sure if this will work for other pointer types!!
@interface NSPointerArray (Helpers)
/**
* Adds pointer to the given object to the array.
*
* @param object Object whose pointer needs to be added to the array.
* If a pointer to this object already exists in the array, you get a duplicate.
* Call containsObject first if you don't want that to happen.
*/
- (void)addObject:(id)object;
/**
* Checks if pointer to the given object is present in the array.
*
* @param object Object whose pointer's presence needs to be checked.
*
* @return YES if pointer to the given object is already present in the array; NO otherwise.
*/
- (BOOL)containsObject:(id)object;
/**
* Removes a pointer that matches the pointer to the passed in object.
*
* @param object An object that's currently in the array. No ill effects if the object is not in the array.
*/
- (void)removeObject:(id)object;
- (void)removeAllNulls;
@end
#import "NSPointerArray+Helpers.h"
@implementation NSPointerArray (Helpers)
- (void)addObject:(id)object
{
[self addPointer:(__bridge void *)object];
}
- (BOOL)containsObject:(id)object
{
// get passed in object's pointer
void * objPtr = (__bridge void *)object;
for (NSUInteger i = 0; i < [self count]; i++) {
void * ptr = [self pointerAtIndex:i];
if (ptr == objPtr) {
return YES;
}
}
return NO;
}
- (void)removeObject:(id)object
{
// get pointer to the passed in object
void * objPtr = (__bridge void *)object;
int objIndex = -1;
for (NSUInteger i = 0; i < [self count]; i++) {
void * ptr = [self pointerAtIndex:i];
if (ptr == objPtr) {
// pointers equal, found our object!
objIndex = i;
break;
}
}
// make sure index is non-nil and not outside bounds
if (objIndex >= 0 && objIndex < [self count]) {
[self removePointerAtIndex:objIndex];
}
}
- (void)removeAllNulls
{
NSMutableSet *indexesToRemove = [NSMutableSet new];
for (NSUInteger i = 0; i < [self count]; i++) {
if (![self pointerAtIndex:i]) { // is the pointer null? then remove it
[indexesToRemove addObject:@(i)];
}
}
for (NSNumber *indexToRemove in indexesToRemove) {
[self removePointerAtIndex:[indexToRemove unsignedIntegerValue]];
}
}
@end
// Some object that pushes out notifications
#import "NSPointerArray+AbstractionHelpers.h"
#import "SampleObject.h"
@interface SampleObject ()
@property (nonatomic, strong) NSPointerArray *delegates;
@end
@implementation SampleObject
- (id)init
{
if (self = [super init]) {
_delegates = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory];
}
return self;
}
- (void)registerDelegate:(id<YourProtocolHere>)delegate
{
if (!delegate) return;
[self addDelegate:delegate];
[self startUpdates];
}
- (void)removeDelegate:(id<YourProtocolHere>)delegate
{
[self.delegates removeObject:delegate];
// if last delegate gets removed, stop listening for updates/nil out depedency objects, if applicable
if ([self.delegates count] == 0) {
[self stopUpdates];
}
}
- (void)addDelegate:(id<YourProtocolHere>)delegate
{
if (![self.delegates containsObject:delegate]) {
[self.delegates addObject:delegate];
}
}
// ... some SampleObject logic here ...
// Helper method that can be called after each round of notifications to see if any delegates left
// Delegates can all eventually become nil due to being weak references
- (BOOL)shouldUpdatesContinue
{
[self.delegates removeAllNulls];
if ([self.delegates count] == 0) {
return NO;
}
return YES;
}
@end
@sgrgrsn
Copy link

sgrgrsn commented Aug 4, 2016

Super useful category - thanks!
I was wondering about the - (void)removeAllNulls;, isn't it the same as the - (void)compact; which is a part of the NSPointerArray?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment