Last active
August 29, 2015 14:01
-
-
Save fjolnir/bac003b62dc3cb734d8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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