Line data Source code
1 0 : /*
2 :
3 : OOCacheManager.m
4 :
5 : Oolite
6 : Copyright (C) 2004-2013 Giles C Williams and contributors
7 :
8 : This program is free software; you can redistribute it and/or
9 : modify it under the terms of the GNU General Public License
10 : as published by the Free Software Foundation; either version 2
11 : of the License, or (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program; if not, write to the Free Software
20 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 : MA 02110-1301, USA.
22 :
23 : */
24 :
25 : #import "OOCacheManager.h"
26 : #import "OOPListParsing.h"
27 : #import "OODeepCopy.h"
28 : #import "OOCollectionExtractors.h"
29 : #import "OOJavaScriptEngine.h"
30 : #import "NSFileManagerOOExtensions.h"
31 :
32 :
33 0 : #define WRITE_ASYNC 1
34 0 : #define PROFILE_WRITES 0
35 :
36 :
37 : // Use the (presumed) most efficient plist format for each platform.
38 : #if OOLITE_MAC_OS_X
39 0 : #define CACHE_PLIST_FORMAT NSPropertyListBinaryFormat_v1_0
40 : #else
41 : #define CACHE_PLIST_FORMAT NSPropertyListGNUstepBinaryFormat
42 : #endif
43 :
44 :
45 : #if WRITE_ASYNC
46 : #import "OOAsyncWorkManager.h"
47 : #endif
48 : #if PROFILE_WRITES
49 : #import "OOProfilingStopwatch.h"
50 : #endif
51 :
52 :
53 0 : static NSString * const kOOLogDataCacheFound = @"dataCache.found";
54 0 : static NSString * const kOOLogDataCacheNotFound = @"dataCache.notFound";
55 0 : static NSString * const kOOLogDataCacheRebuild = @"dataCache.rebuild";
56 0 : static NSString * const kOOLogDataCacheWriteSuccess = @"dataCache.write.success";
57 0 : static NSString * const kOOLogDataCacheWriteFailed = @"dataCache.write.failed";
58 0 : static NSString * const kOOLogDataCacheRetrieveSuccess = @"dataCache.retrieve.success";
59 0 : static NSString * const kOOLogDataCacheRetrieveFailed = @"dataCache.retrieve.failed";
60 0 : static NSString * const kOOLogDataCacheSetSuccess = @"dataCache.set.success";
61 0 : static NSString * const kOOLogDataCacheSetFailed = @"dataCache.set.failed";
62 0 : static NSString * const kOOLogDataCacheRemoveSuccess = @"dataCache.remove.success";
63 0 : static NSString * const kOOLogDataCacheClearSuccess = @"dataCache.clear.success";
64 0 : static NSString * const kOOLogDataCacheBuildPathError = @"dataCache.write.buildPath.failed";
65 0 : static NSString * const kOOLogDataCacheSerializationError = @"dataCache.write.serialize.failed";
66 :
67 0 : static NSString * const kCacheKeyVersion = @"version";
68 0 : static NSString * const kCacheKeyEndianTag = @"endian tag";
69 0 : static NSString * const kCacheKeyFormatVersion = @"format version";
70 0 : static NSString * const kCacheKeyCaches = @"caches";
71 :
72 :
73 0 : enum
74 : {
75 : kEndianTagValue = 0x0123456789ABCDEFULL,
76 : kFormatVersionValue = 219
77 : };
78 :
79 :
80 0 : static OOCacheManager *sSingleton = nil;
81 :
82 :
83 : @interface OOCacheManager (Private)
84 :
85 0 : - (void)loadCache;
86 0 : - (void)write;
87 0 : - (void)clear;
88 0 : - (BOOL)dirty;
89 0 : - (void)markClean;
90 :
91 0 : - (NSDictionary *)loadDict;
92 0 : - (BOOL)writeDict:(NSDictionary *)inDict;
93 :
94 0 : - (void)buildCachesFromDictionary:(NSDictionary *)inDict;
95 0 : - (NSDictionary *)dictionaryOfCaches;
96 :
97 0 : - (BOOL)directoryExists:(NSString *)inPath create:(BOOL)inCreate;
98 :
99 : @end
100 :
101 :
102 : @interface OOCacheManager (PlatformSpecific)
103 :
104 0 : - (NSString *)cachePathCreatingIfNecessary:(BOOL)inCreate;
105 :
106 : @end
107 :
108 :
109 : #if WRITE_ASYNC
110 0 : @interface OOAsyncCacheWriter: NSObject <OOAsyncWorkTask>
111 : {
112 : @private
113 : NSDictionary *_cacheContents;
114 0 : }
115 :
116 : - (id) initWithCacheContents:(NSDictionary *)cacheContents;
117 0 :
118 : @end
119 : #endif
120 :
121 :
122 : @implementation OOCacheManager
123 :
124 : - (id)init
125 0 : {
126 : self = [super init];
127 : if (self != nil)
128 : {
129 : _permitWrites = YES;
130 : [self loadCache];
131 : }
132 : return self;
133 : }
134 :
135 :
136 : - (void)dealloc
137 0 : {
138 : [self clear];
139 :
140 : [super dealloc];
141 : }
142 :
143 :
144 : - (NSString *)description
145 0 : {
146 : return [NSString stringWithFormat:@"<%@ %p>{dirty=%s}", [self class], self, [self dirty] ? "yes" : "no"];
147 : }
148 :
149 :
150 : + (OOCacheManager *) sharedCache
151 : {
152 : // NOTE: assumes single-threaded access.
153 : if (sSingleton == nil)
154 : {
155 : sSingleton = [[self alloc] init];
156 : }
157 :
158 : return sSingleton;
159 : }
160 :
161 :
162 : - (id)objectForKey:(NSString *)inKey inCache:(NSString *)inCacheKey
163 : {
164 : NSMutableDictionary *cache = nil;
165 : id result = nil;
166 :
167 : NSParameterAssert(inKey != nil && inCacheKey != nil);
168 :
169 : cache = [_caches objectForKey:inCacheKey];
170 : if (cache != nil)
171 : {
172 : result = [cache objectForKey:inKey];
173 : if (result != nil)
174 : {
175 : OODebugLog(kOOLogDataCacheRetrieveSuccess, @"Retrieved \"%@\" cache object %@.", inCacheKey, inKey);
176 : }
177 : else
178 : {
179 : OODebugLog(kOOLogDataCacheRetrieveFailed, @"Failed to retrieve \"%@\" cache object %@ -- no such entry.", inCacheKey, inKey);
180 : }
181 : }
182 : else
183 : {
184 : OODebugLog(kOOLogDataCacheRetrieveFailed, @"Failed to retrieve \"%@\" cache object %@ -- no such cache.", inCacheKey, inKey);
185 : }
186 :
187 : return result;
188 : }
189 :
190 :
191 :
192 : - (void)setObject:(id)inObject forKey:(NSString *)inKey inCache:(NSString *)inCacheKey
193 : {
194 : NSMutableDictionary *cache = nil;
195 :
196 : NSParameterAssert(inObject != nil && inKey != nil && inCacheKey != nil);
197 :
198 : if (EXPECT_NOT(_caches == nil)) return;
199 :
200 : cache = [_caches objectForKey:inCacheKey];
201 : if (cache == nil)
202 : {
203 : cache = [NSMutableDictionary dictionary];
204 : if (cache == nil)
205 : {
206 : OODebugLog(kOOLogDataCacheSetFailed, @"Failed to create cache for key \"%@\".", inCacheKey);
207 : return;
208 : }
209 : [_caches setObject:cache forKey:inCacheKey];
210 : }
211 :
212 : [cache setObject:inObject forKey:inKey];
213 : _dirty = YES;
214 : OODebugLog(kOOLogDataCacheSetSuccess, @"Updated entry %@ in cache \"%@\".", inKey, inCacheKey);
215 : }
216 :
217 :
218 : - (void)removeObjectForKey:(NSString *)inKey inCache:(NSString *)inCacheKey
219 : {
220 : NSMutableDictionary *cache = nil;
221 :
222 : NSParameterAssert(inKey != nil && inCacheKey != nil);
223 :
224 : cache = [_caches objectForKey:inCacheKey];
225 : if (cache != nil)
226 : {
227 : if (nil != [cache objectForKey:inKey])
228 : {
229 : [cache removeObjectForKey:inKey];
230 : _dirty = YES;
231 : OODebugLog(kOOLogDataCacheRemoveSuccess, @"Removed entry keyed %@ from cache \"%@\".", inKey, inCacheKey);
232 : }
233 : else
234 : {
235 : OODebugLog(kOOLogDataCacheRemoveSuccess, @"No need to remove non-existent entry keyed %@ from cache \"%@\".", inKey, inCacheKey);
236 : }
237 : }
238 : else
239 : {
240 : OODebugLog(kOOLogDataCacheRemoveSuccess, @"No need to remove entry keyed %@ from non-existent cache \"%@\".", inKey, inCacheKey);
241 : }
242 : }
243 :
244 :
245 : - (void)clearCache:(NSString *)inCacheKey
246 : {
247 : NSParameterAssert(inCacheKey != nil);
248 :
249 : if (nil != [_caches objectForKey:inCacheKey])
250 : {
251 : [_caches removeObjectForKey:inCacheKey];
252 : _dirty = YES;
253 : OODebugLog(kOOLogDataCacheClearSuccess, @"Cleared cache \"%@\".", inCacheKey);
254 : }
255 : else
256 : {
257 : OODebugLog(kOOLogDataCacheClearSuccess, @"No need to clear non-existent cache \"%@\".", inCacheKey);
258 : }
259 : }
260 :
261 :
262 : - (void)clearAllCaches
263 : {
264 : [self clear];
265 : _caches = [[NSMutableDictionary alloc] init];
266 : _dirty = YES;
267 : }
268 :
269 :
270 : - (void) reloadAllCaches
271 : {
272 : [self clear];
273 : [self loadCache];
274 : }
275 :
276 :
277 : - (void)flush
278 : {
279 : if (_permitWrites && [self dirty] && _scheduledWrite == nil)
280 : {
281 : [self write];
282 : [self markClean];
283 : }
284 : }
285 :
286 :
287 : - (void)finishOngoingFlush
288 : {
289 : #if WRITE_ASYNC
290 : [[OOAsyncWorkManager sharedAsyncWorkManager] waitForTaskToComplete:_scheduledWrite];
291 : #endif
292 : }
293 :
294 :
295 : - (void)setAllowCacheWrites:(BOOL)flag
296 : {
297 : _permitWrites = (flag != NO);
298 : }
299 :
300 :
301 : - (NSString *)cacheDirectoryPathCreatingIfNecessary:(BOOL)create
302 : {
303 : /* Construct the path to the directory for cache files, which is:
304 : ~/Library/Caches/org.aegidian.oolite/
305 : or
306 : ~/GNUStep/Library/Caches/org.aegidian.oolite/
307 : In addition to generally being the right place to put caches,
308 : ~/Library/Caches has the particular advantage of not being indexed by
309 : Spotlight or backed up by Time Machine.
310 : */
311 : NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
312 : if (![self directoryExists:cachePath create:create]) return nil;
313 :
314 : #if !OOLITE_MAC_OS_X
315 : // the old cache file on GNUstep was one level up, so remove it if it exists
316 : [[NSFileManager defaultManager] removeFileAtPath:[cachePath stringByAppendingPathComponent:@"Oolite-cache.plist"] handler:nil];
317 : #endif
318 :
319 : cachePath = [cachePath stringByAppendingPathComponent:@"org.aegidian.oolite"];
320 : if (![self directoryExists:cachePath create:create]) return nil;
321 : return cachePath;
322 : }
323 :
324 : @end
325 :
326 :
327 : @implementation OOCacheManager (Private)
328 :
329 : - (void)loadCache
330 : {
331 : NSDictionary *cache = nil;
332 : NSString *cacheVersion = nil;
333 : NSString *ooliteVersion = nil;
334 : NSData *endianTag = nil;
335 : NSNumber *formatVersion = nil;
336 : BOOL accept = YES;
337 : uint64_t endianTagValue = 0;
338 :
339 : ooliteVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
340 :
341 : [self clear];
342 :
343 : cache = [self loadDict];
344 : if (cache != nil)
345 : {
346 : // We have a cache
347 : OOLog(kOOLogDataCacheFound, @"%@", @"Found data cache.");
348 : OOLogIndentIf(kOOLogDataCacheFound);
349 :
350 : cacheVersion = [cache objectForKey:kCacheKeyVersion];
351 : if (![cacheVersion isEqual:ooliteVersion])
352 : {
353 : OOLog(kOOLogDataCacheRebuild, @"Data cache version (%@) does not match Oolite version (%@), rebuilding cache.", cacheVersion, ooliteVersion);
354 : accept = NO;
355 : }
356 :
357 : formatVersion = [cache objectForKey:kCacheKeyFormatVersion];
358 : if (accept && [formatVersion unsignedIntValue] != kFormatVersionValue)
359 : {
360 : OOLog(kOOLogDataCacheRebuild, @"Data cache format (%@) is not supported format (%u), rebuilding cache.", formatVersion, kFormatVersionValue);
361 : accept = NO;
362 : }
363 :
364 : if (accept)
365 : {
366 : endianTag = [cache objectForKey:kCacheKeyEndianTag];
367 : if (![endianTag isKindOfClass:[NSData class]] || [endianTag length] != sizeof endianTagValue)
368 : {
369 : OOLog(kOOLogDataCacheRebuild, @"%@", @"Data cache endian tag is invalid, rebuilding cache.");
370 : accept = NO;
371 : }
372 : else
373 : {
374 : endianTagValue = *(const uint64_t *)[endianTag bytes];
375 : if (endianTagValue != kEndianTagValue)
376 : {
377 : OOLog(kOOLogDataCacheRebuild, @"%@", @"Data cache endianness is inappropriate for this system, rebuilding cache.");
378 : accept = NO;
379 : }
380 : }
381 : }
382 :
383 : if (accept)
384 : {
385 : // We have a cache, and it's the right format.
386 : [self buildCachesFromDictionary:[cache objectForKey:kCacheKeyCaches]];
387 : }
388 :
389 : OOLogOutdentIf(kOOLogDataCacheFound);
390 : }
391 : else
392 : {
393 : // No cache
394 : OOLog(kOOLogDataCacheNotFound, @"%@", @"No data cache found, starting from scratch.");
395 : }
396 :
397 : // If loading failed, or there was a version or endianness conflict
398 : if (_caches == nil) _caches = [[NSMutableDictionary alloc] init];
399 : [self markClean];
400 : }
401 :
402 :
403 : - (void)write
404 : {
405 : NSMutableDictionary *newCache = nil;
406 : NSString *ooliteVersion = nil;
407 : NSData *endianTag = nil;
408 : NSNumber *formatVersion = nil;
409 : NSDictionary *pListRep = nil;
410 : uint64_t endianTagValue = kEndianTagValue;
411 :
412 : if (_caches == nil) return;
413 : if (_scheduledWrite != nil) return;
414 :
415 : #if PROFILE_WRITES
416 : OOProfilingStopwatch *stopwatch = [OOProfilingStopwatch stopwatch];
417 : #endif
418 :
419 : #if WRITE_ASYNC
420 : OOLog(@"dataCache.willWrite", @"%@", @"Scheduling data cache write.");
421 : #else
422 : OOLog(@"dataCache.willWrite", @"%@", @"About to write cache.");
423 : #endif
424 :
425 : ooliteVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
426 : endianTag = [NSData dataWithBytes:&endianTagValue length:sizeof endianTagValue];
427 : formatVersion = [NSNumber numberWithUnsignedInt:kFormatVersionValue];
428 :
429 : pListRep = [self dictionaryOfCaches];
430 : if (ooliteVersion == nil || endianTag == nil || formatVersion == nil || pListRep == nil)
431 : {
432 : OOLog(@"dataCache.cantWrite", @"%@", @"Failed to write data cache -- prerequisites not fulfilled. This is an internal error, please report it.");
433 : return;
434 : }
435 :
436 : newCache = [NSMutableDictionary dictionaryWithCapacity:4];
437 : [newCache setObject:ooliteVersion forKey:kCacheKeyVersion];
438 : [newCache setObject:formatVersion forKey:kCacheKeyFormatVersion];
439 : [newCache setObject:endianTag forKey:kCacheKeyEndianTag];
440 : [newCache setObject:pListRep forKey:kCacheKeyCaches];
441 :
442 : #if PROFILE_WRITES && !WRITE_ASYNC
443 : OOTimeDelta prepareT = [stopwatch reset];
444 : #endif
445 :
446 : #if WRITE_ASYNC
447 : NSDictionary *cacheData = newCache;
448 : _scheduledWrite = [[OOAsyncCacheWriter alloc] initWithCacheContents:cacheData];
449 :
450 : #if PROFILE_WRITES
451 : OOTimeDelta endT = [stopwatch reset];
452 : OOLog(@"dataCache.profile", @"Time to prepare cache data: %g seconds.", endT);
453 : #endif
454 :
455 : [[OOAsyncWorkManager sharedAsyncWorkManager] addTask:_scheduledWrite priority:kOOAsyncPriorityLow];
456 : #else
457 : #if PROFILE_WRITES
458 : OOLog(@"dataCache.profile", @"Time to prepare cache data: %g seconds.", prepareT);
459 : #endif
460 :
461 : if ([self writeDict:newCache])
462 : {
463 : [self markClean];
464 : OOLog(kOOLogDataCacheWriteSuccess, @"%@", @"Wrote data cache.");
465 : }
466 : else
467 : {
468 : OOLog(kOOLogDataCacheWriteFailed, @"%@", @"Failed to write data cache.");
469 : }
470 : #endif
471 : }
472 :
473 :
474 : - (void)clear
475 : {
476 : [_caches release];
477 : _caches = nil;
478 : }
479 :
480 :
481 : - (BOOL)dirty
482 : {
483 : return _dirty;
484 : }
485 :
486 :
487 : - (void)markClean
488 : {
489 : _dirty = NO;
490 : }
491 :
492 :
493 : - (NSDictionary *)loadDict
494 : {
495 : NSString *path = nil;
496 : NSData *data = nil;
497 : NSString *errorString = nil;
498 : id contents = nil;
499 :
500 : path = [self cachePathCreatingIfNecessary:NO];
501 : if (path == nil) return nil;
502 :
503 : @try
504 : {
505 : data = [NSData dataWithContentsOfFile:path];
506 : if (data == nil) return nil;
507 :
508 : contents = [NSPropertyListSerialization propertyListFromData:data
509 : mutabilityOption:NSPropertyListImmutable
510 : format:NULL
511 : errorDescription:&errorString];
512 : }
513 : @catch (NSException *exception)
514 : {
515 : errorString = [exception reason];
516 : contents = nil;
517 : }
518 :
519 : if (errorString != nil)
520 : {
521 : OOLog(@"dataCache.badData", @"Could not read data cache: %@", errorString);
522 : #if OOLITE_RELEASE_PLIST_ERROR_STRINGS
523 : [errorString release];
524 : #endif
525 : return nil;
526 : }
527 : if (![contents isKindOfClass:[NSDictionary class]]) return nil;
528 :
529 : return contents;
530 : }
531 :
532 :
533 : - (BOOL)writeDict:(NSDictionary *)inDict
534 : {
535 : NSString *path = nil;
536 : NSData *plist = nil;
537 : NSString *errorDesc = nil;
538 :
539 : path = [self cachePathCreatingIfNecessary:YES];
540 : if (path == nil) return NO;
541 :
542 : #if PROFILE_WRITES
543 : OOProfilingStopwatch *stopwatch = [OOProfilingStopwatch stopwatch];
544 : #endif
545 :
546 : plist = [NSPropertyListSerialization dataFromPropertyList:inDict format:CACHE_PLIST_FORMAT errorDescription:&errorDesc];
547 : if (plist == nil)
548 : {
549 : #if OOLITE_RELEASE_PLIST_ERROR_STRINGS
550 : [errorDesc autorelease];
551 : #endif
552 : OOLog(kOOLogDataCacheSerializationError, @"Could not convert data cache to property list data: %@", errorDesc);
553 : return NO;
554 : }
555 :
556 : #if PROFILE_WRITES
557 : OOTimeDelta serializeT = [stopwatch reset];
558 : #endif
559 :
560 : BOOL result = [plist writeToFile:path atomically:NO];
561 :
562 : #if PROFILE_WRITES
563 : OOTimeDelta writeT = [stopwatch reset];
564 :
565 : OOLog(@"dataCache.profile", @"Time to serialize cache: %g seconds. Time to write data: %g seconds.", serializeT, writeT);
566 : #endif
567 :
568 : #if WRITE_ASYNC
569 : DESTROY(_scheduledWrite);
570 : #endif
571 : return result;
572 : }
573 :
574 :
575 : - (void)buildCachesFromDictionary:(NSDictionary *)inDict
576 : {
577 : NSEnumerator *keyEnum = nil;
578 : id key = nil;
579 : id value = nil;
580 : NSMutableDictionary *cache = nil;
581 :
582 : if (inDict == nil ) return;
583 :
584 : [_caches release];
585 : _caches = [[NSMutableDictionary alloc] initWithCapacity:[inDict count]];
586 :
587 : for (keyEnum = [inDict keyEnumerator]; (key = [keyEnum nextObject]); )
588 : {
589 : value = [inDict oo_dictionaryForKey:key];
590 : if (value != nil)
591 : {
592 : cache = [NSMutableDictionary dictionaryWithDictionary:value];
593 : if (cache != nil)
594 : {
595 : [_caches setObject:cache forKey:key];
596 : }
597 : }
598 : }
599 : }
600 :
601 :
602 : - (NSDictionary *)dictionaryOfCaches
603 : {
604 : return [OODeepCopy(_caches) autorelease];
605 : }
606 :
607 :
608 : - (BOOL)directoryExists:(NSString *)inPath create:(BOOL)inCreate
609 : {
610 : BOOL exists, directory;
611 : NSFileManager *fmgr = [NSFileManager defaultManager];
612 :
613 : exists = [fmgr fileExistsAtPath:inPath isDirectory:&directory];
614 :
615 : if (exists && !directory)
616 : {
617 : OOLog(kOOLogDataCacheBuildPathError, @"Expected %@ to be a folder, but it is a file.", inPath);
618 : return NO;
619 : }
620 : if (!exists)
621 : {
622 : if (!inCreate) return NO;
623 : if (![fmgr oo_createDirectoryAtPath:inPath attributes:nil])
624 : {
625 : OOLog(kOOLogDataCacheBuildPathError, @"Could not create folder %@.", inPath);
626 : return NO;
627 : }
628 : }
629 :
630 : return YES;
631 : }
632 :
633 :
634 : #if OOLITE_MAC_OS_X
635 :
636 : - (NSString *)cachePathCreatingIfNecessary:(BOOL)create
637 0 : {
638 : NSString *cachePath = [self cacheDirectoryPathCreatingIfNecessary:create];
639 : return [cachePath stringByAppendingPathComponent:@"Data Cache.plist"];
640 : }
641 :
642 : #else
643 :
644 : - (NSString *)cachePathCreatingIfNecessary:(BOOL)create
645 : {
646 : NSString *cachePath = [self cacheDirectoryPathCreatingIfNecessary:create];
647 : return [cachePath stringByAppendingPathComponent:@"Oolite-cache.plist"];
648 : }
649 :
650 : #endif
651 :
652 : @end
653 :
654 :
655 : @implementation OOCacheManager (Singleton)
656 :
657 : /* Canonical singleton boilerplate.
658 : See Cocoa Fundamentals Guide: Creating a Singleton Instance.
659 : See also +sharedCache above.
660 :
661 : NOTE: assumes single-threaded access.
662 : */
663 :
664 : + (id)allocWithZone:(NSZone *)inZone
665 0 : {
666 : if (sSingleton == nil)
667 : {
668 : sSingleton = [super allocWithZone:inZone];
669 : return sSingleton;
670 : }
671 : return nil;
672 : }
673 :
674 :
675 : - (id)copyWithZone:(NSZone *)inZone
676 0 : {
677 : return self;
678 : }
679 :
680 :
681 : - (id)retain
682 0 : {
683 : return self;
684 : }
685 :
686 :
687 : - (NSUInteger)retainCount
688 0 : {
689 : return UINT_MAX;
690 : }
691 :
692 :
693 : - (void)release
694 0 : {}
695 :
696 :
697 : - (id)autorelease
698 0 : {
699 : return self;
700 : }
701 :
702 : @end
703 :
704 :
705 : #if WRITE_ASYNC
706 : @implementation OOAsyncCacheWriter
707 :
708 : - (id) initWithCacheContents:(NSDictionary *)cacheContents
709 : {
710 : if ((self = [super init]))
711 : {
712 : _cacheContents = [cacheContents copy];
713 : if (_cacheContents == nil)
714 : {
715 : [self release];
716 : self = nil;
717 : }
718 : }
719 :
720 : return self;
721 : }
722 :
723 :
724 : - (void) dealloc
725 0 : {
726 : DESTROY(_cacheContents);
727 :
728 : [super dealloc];
729 : }
730 :
731 :
732 : - (void) performAsyncTask
733 0 : {
734 : if ([[OOCacheManager sharedCache] writeDict:_cacheContents])
735 : {
736 : OOLog(kOOLogDataCacheWriteSuccess, @"%@", @"Wrote data cache.");
737 : }
738 : else
739 : {
740 : OOLog(kOOLogDataCacheWriteFailed, @"%@", @"Failed to write data cache.");
741 : }
742 : DESTROY(_cacheContents);
743 : }
744 :
745 :
746 : - (void) completeAsyncTask
747 0 : {
748 : // Don't need to do anything, but this needs to be here so we can wait on it.
749 : }
750 :
751 : @end
752 : #endif // WRITE_ASYNC
|