Skip to content

Instantly share code, notes, and snippets.

@fjolnir
Last active August 29, 2015 14:01
Show Gist options
  • Save fjolnir/bac003b62dc3cb734d8f to your computer and use it in GitHub Desktop.
Save fjolnir/bac003b62dc3cb734d8f to your computer and use it in GitHub Desktop.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
typedef id (^FLazyProxyResolver)();
@interface FLazyProxy : NSProxy
@end
@interface FLazyProxy () {
FLazyProxyResolver _resolver;
id _object;
BOOL _resolved;
}
@end
@implementation FLazyProxy
+ (instancetype)proxyWithBlock:(FLazyProxyResolver const)aResolver
{
FLazyProxy * const proxy = [self alloc];
NSParameterAssert(aResolver);
proxy->_resolver = aResolver;
return proxy;
}
- (id)_cy_object
{
if(!_resolved) {
_resolved = YES;
_object = _resolver();
}
return _object;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
[anInvocation setTarget:[self _cy_object]];
[anInvocation invoke];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return [[self _cy_object] methodSignatureForSelector:aSelector];
}
- (NSString *)description { return [[self _cy_object] description]; }
@end
// Cannot return nil.
typedef id (^FLazyArrayResolver)(NSUInteger aIdx);
// Warning: In no way thread safe.
@interface FLazyArray : NSObject
@property(readonly) NSUInteger count;
+ (FLazyArray *)arrayWithCount:(NSUInteger)aCount resolver:(FLazyArrayResolver)aResolver;
- (id)objectAtIndex:(NSUInteger)aIdx;
- (id)objectAtIndexedSubscript:(NSUInteger)aIdx;
@end
@interface FLazyArray () {
FLazyArrayResolver _resolver;
NSPointerArray *_array;
NSMutableIndexSet *_resolvedIndexes;
}
@end
@implementation FLazyArray
@dynamic count;
+ (FLazyArray *)arrayWithCount:(NSUInteger const)aCount resolver:(FLazyArrayResolver const)aResolver
{
FLazyArray * const array = [self new];
array->_resolver = aResolver;
array->_array = [NSPointerArray strongObjectsPointerArray];
array->_array.count = aCount;
return array;
}
- (id)init
{
if((self = [super init]))
_resolvedIndexes = [NSMutableIndexSet new];
return self;
}
- (void)_resolveIndex:(NSUInteger const)aIdx
{
if([_resolvedIndexes containsIndex:aIdx])
return;
id const object = _resolver(aIdx);
NSAssert(object, @"Tried to insert nil into array!");
[_array replacePointerAtIndex:aIdx withPointer:(__bridge void*)object];
[_resolvedIndexes addIndex:aIdx];
}
- (id)objectAtIndex:(NSUInteger const)aIdx
{
id object = (id)[_array pointerAtIndex:aIdx];
if(!object) {
object = [FLazyProxy proxyWithBlock:^{
[self _resolveIndex:aIdx];
return (id)[_array pointerAtIndex:aIdx];
}];
[_array replacePointerAtIndex:aIdx withPointer:(__bridge void*)object];
}
return object;
}
- (id)objectAtIndexedSubscript:(NSUInteger const)aIdx
{
return [self objectAtIndex:aIdx];
}
- (NSUInteger)count
{
return [_array count];
}
- (NSString *)description
{
NSMutableString * const desc = [NSMutableString stringWithFormat:@"<%@: %p\n", [self class], self];
for(NSUInteger i = 0; i < [_array count]; ++i) {
[desc appendFormat:@" %@,\n", [_resolvedIndexes containsIndex:i]
? (id)[_array pointerAtIndex:i]
: @"(unresolved)"];
}
[desc appendString:@">"];
return desc;
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
FLazyArray *arr = [FLazyArray arrayWithCount:20 resolver:^(NSUInteger idx){
NSLog(@"Resolving %lu", idx);
return @(idx);
}];
NSLog(@"%@ %@ %@", arr[5], arr[10], arr);
}
_cells = [FLazyArray arrayWithCount:[_datasource numberOfCellsInView:self] resolver:^(NSUInteger idx) { return [_datasource cellForIndex:idx]; }];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment