Skip to content

Commit

Permalink
new marks to separate iOS futures
Browse files Browse the repository at this point in the history
use [self futureHasResolved] to check future status instead of check _resolved variable directly
override futureValue function to return retained and autorelease object. That is neccessary because _value can be invalidated at any time.
pass [NSThread currentThread] to the processMemoryWarning block to unlock _lock in appropriate thread.
check future class in +initialize method. Thanks to the Mike's Friday Q&A 2010-08-27
rename encode -> archive
rename decode -> unarchive
remove encodeValue and decodeValue
add more comments for _IKMemoryAwareFuture and _IKAutoArchivingMemoryAwareFuture
  • Loading branch information
Kentzo committed Aug 29, 2010
1 parent 9e30451 commit c12cfca
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 81 deletions.
90 changes: 40 additions & 50 deletions MAFuture.m
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ id MALazyFuture(id (^block)(void))
return [[[_MALazyBlockFuture alloc] initWithBlock: block] autorelease];
}

#pragma mark -
#pragma mark iOS Futures

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_3_2

Expand All @@ -133,15 +136,15 @@ - (void)setIsObserving:(BOOL)newIsObserving {
[_lock lock];
if (newIsObserving && isManuallyStopped) {
isManuallyStopped = NO;
if (_resolved) {
if ([self futureHasResolved]) {
// If future is resolved set isObserving back to YES.
// Otherwise this will be set to YES just after resolving.
[self setIsObservingUnlocked:YES];
}
}
else if (!newIsObserving && !isManuallyStopped) {
isManuallyStopped = YES;
if (_resolved) {
if ([self futureHasResolved]) {
// If future is resolved set isObserving to NO.
// Otherwise this is already set to NO.
[self setIsObservingUnlocked:NO];
Expand All @@ -151,6 +154,11 @@ - (void)setIsObserving:(BOOL)newIsObserving {
}


- (id)futureValue {
return [[[super futureValue] retain] autorelease];
}


- (void)setIsObservingUnlocked:(BOOL)newIsObserving {

if (isObserving != newIsObserving) {
Expand Down Expand Up @@ -189,18 +197,19 @@ - (id)resolveFuture {

- (void)processMemoryWarning {
[_lock lock];
// TODO: I'm not sure about the thread that receives UIApplicationDidReceiveMemoryWarningNotification.
[self setIsObservingUnlocked:NO];
NSThread *thread = [NSThread currentThread];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self processMemoryWarningUnlocked];
dispatch_async(dispatch_get_main_queue(), ^{ [_lock unlock]; });
[_lock performSelector:@selector(unlock) onThread:thread withObject:nil waitUntilDone:NO];
});
}


- (void)processMemoryWarningUnlocked {
[self setIsObservingUnlocked:NO];
[_value release], _value = nil;
// TODO: must be checked when resolvation algorithm is changed.
_resolved = NO;
[_value release], _value = nil;
}

@end
Expand All @@ -227,9 +236,6 @@ BOOL IKMemoryAwareFutureIsObserving(id future) {
return [future isObserving];
}

#pragma mark -
#pragma mark Archiving IKMAFutures

NSString* IKMemoryAwareFuturesDirectory() {
static NSString* FuturesDirectory = nil;
if (FuturesDirectory == nil) {
Expand All @@ -245,23 +251,24 @@ BOOL IKMemoryAwareFutureIsObserving(id future) {
@implementation _IKAutoArchivingMemoryAwareFuture

+ (void)initialize {

NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *futuresDirectory = IKMemoryAwareFuturesDirectory();
if (self == [_IKAutoArchivingMemoryAwareFuture class]) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *futuresDirectory = IKMemoryAwareFuturesDirectory();
#if ENABLE_LOGGING
NSError *error = nil;
if (![fileManager removeItemAtPath:futuresDirectory error:&error]) {
LOG(@"IKAAMAF: Error is occured while trying to remove old futures directory at path \"%@\": %@",
futuresDirectory, [error localizedDescription]);
}
if (![fileManager createDirectoryAtPath:futuresDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
LOG(@"IKAAMAF: Error is occured while trying to create temporary directory for futures at path \"%@\": %@",
futuresDirectory, [error localizedDescription]);
}
NSError *error = nil;
if (![fileManager removeItemAtPath:futuresDirectory error:&error]) {
LOG(@"IKAAMAF: Error is occured while trying to remove old futures directory at path \"%@\": %@",
futuresDirectory, [error localizedDescription]);
}
if (![fileManager createDirectoryAtPath:futuresDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
LOG(@"IKAAMAF: Error is occured while trying to create temporary directory for futures at path \"%@\": %@",
futuresDirectory, [error localizedDescription]);
}
#else
[fileManager removeItemAtPath:futuresDirectory error:NULL];
[fileManager createDirectoryAtPath:futuresDirectory withIntermediateDirectories:NO attributes:nil error:NULL];
[fileManager removeItemAtPath:futuresDirectory error:NULL];
[fileManager createDirectoryAtPath:futuresDirectory withIntermediateDirectories:NO attributes:nil error:NULL];
#endif
}
}


Expand All @@ -284,13 +291,10 @@ - (id)resolveFuture {
if(![self futureHasResolved])
{
// Try to decode object from file.
if (![self decodeValueUnlocked]) {
if (![self unarchiveValueUnlocked]) {
// If cannot to decode object, create it.
[self setFutureValueUnlocked: _block()];
}
else {
_resolved = YES;
}

if (!isManuallyStopped) {
[self setIsObservingUnlocked:YES];
Expand All @@ -302,20 +306,12 @@ - (id)resolveFuture {


- (void)processMemoryWarningUnlocked {
[self encodeValueUnlocked];
[self archiveValueUnlocked];
[super processMemoryWarningUnlocked];
}


- (BOOL)encodeValue {
[_lock lock];
BOOL result = [self encodeValueUnlocked];
[_lock unlock];
return result;
}


- (BOOL)encodeValueUnlocked {
- (BOOL)archiveValueUnlocked {
#if ENABLE_LOGGING
BOOL result = [NSKeyedArchiver archiveRootObject:_value toFile:IKMemoryAwareFuturePath(self)];
if (!result) {
Expand All @@ -328,23 +324,17 @@ - (BOOL)encodeValueUnlocked {
}


- (BOOL)decodeValue {
[_lock lock];
BOOL result = [self decodeValueUnlocked];
[_lock unlock];
return result;
}


- (BOOL)decodeValueUnlocked {
_value = [[NSKeyedUnarchiver unarchiveObjectWithFile:IKMemoryAwareFuturePath(self)] retain];
- (BOOL)unarchiveValueUnlocked {
id value = [[NSKeyedUnarchiver unarchiveObjectWithFile:IKMemoryAwareFuturePath(self)] retain];
if (value != nil) {
[self setFutureValueUnlocked:value];
}
#if ENABLE_LOGGING
if (_value == nil) {
else {
LOG(@"IKAAMAF: Cannot decode value at path \"%@\"", IKMemoryAwareFuturePath(self));
}
#endif
_resolved = (_value != nil);
return _resolved;
return [self futureHasResolved];
}

@end
Expand Down
48 changes: 17 additions & 31 deletions MAFutureInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,24 @@
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_3_2

/*
Subclassing Notes:
Template for resolveFuture method:
[_lock lock];
if(![self futureHasResolved])
{
// ---> Insert your code here <---
// Somewhere in your code you should place [self setFutureValueUnlocked: _block()];
if (!isManuallyStopped) {
[self setIsObservingUnlocked:YES];
}
}
[_lock unlock];
return _value;
*/
@interface _IKMemoryAwareFuture : _MALazyBlockFuture {
BOOL isObserving;
BOOL isManuallyStopped;
}

/*
@abstract Use this property to control observing of memory warning notifications.
*/
@property BOOL isObserving;

/*
@abstract Called in response to UIApplicationDidReceiveMemoryWarningNotification.
@discussion Starts processMemoryWarningUnlocked on background thread.
*/
- (void)processMemoryWarning;

/*
@abstract Releases future and sets _resolved to NO.
*/
- (void)processMemoryWarningUnlocked;

/*
Expand All @@ -63,21 +54,16 @@ NSString* IKMemoryAwareFuturePath(id future);
@interface _IKAutoArchivingMemoryAwareFuture : _IKMemoryAwareFuture

/*
@abstract Encode value while holding the lock
*/
- (BOOL)encodeValue;
/*
@abstract Encode value without holding the lock
@abstract Archives value to the disk.
@result YES if value is archived without errors. Otherwise NO.
*/
- (BOOL)encodeValueUnlocked;
/*
@abstract Decode value while holding the lock
*/
- (BOOL)decodeValue;
- (BOOL)archiveValueUnlocked;

/*
@abstract Decode value without holding the lock
@abstract Unarchives value from the disk.
@result YES if value is unarchived without errors. If either archive for future doesn't exist or error is occured, returns NO.
*/
- (BOOL)decodeValueUnlocked;
- (BOOL)unarchiveValueUnlocked;

@end

Expand Down

0 comments on commit c12cfca

Please sign in to comment.