/core/externals/update-engine/externals/google-toolbox-for-mac/AppKit/GTMIBArray.m
http://macfuse.googlecode.com/ · Objective C · 166 lines · 89 code · 26 blank · 51 comment · 17 complexity · 2dc28c8cdec8aac43facc1e275819460 MD5 · raw file
- //
- // GTMIBArray.m
- //
- // Copyright 2009 Google Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License"); you may not
- // use this file except in compliance with the License. You may obtain a copy
- // of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- // License for the specific language governing permissions and limitations under
- // the License.
- //
- #import "GTMIBArray.h"
- #import "GTMDefines.h"
- @implementation GTMIBArray
- - (void)dealloc {
- [realArray_ release];
- [super dealloc];
- }
- - (void)setupRealArray {
- #ifdef DEBUG
- // It is very easy to create a cycle if you are chaining these in IB, so in
- // debug builds, we try to catch this to inform the developer. Use -[NSArray
- // indexOfObjectIdenticalTo:] to get pointer comparisons instead of object
- // equality.
- static NSMutableArray *ibArraysBuilding = nil;
- if (!ibArraysBuilding) {
- ibArraysBuilding = [[NSMutableArray alloc] init];
- }
- _GTMDevAssert([ibArraysBuilding indexOfObjectIdenticalTo:self] == NSNotFound,
- @"There is a cycle in your GTMIBArrays!");
- [ibArraysBuilding addObject:self];
- #endif // DEBUG
- // Build the array up.
- NSMutableArray *builder = [NSMutableArray array];
- Class ibArrayClass = [GTMIBArray class];
- id objs[] = {
- object1_, object2_, object3_, object4_, object5_,
- };
- for (size_t idx = 0 ; idx < sizeof(objs) / (sizeof(objs[0])) ; ++idx) {
- id obj = objs[idx];
- if (obj) {
- if ([obj isKindOfClass:ibArrayClass]) {
- [builder addObjectsFromArray:obj];
- } else {
- [builder addObject:obj];
- }
- }
- }
- #ifdef DEBUG
- [ibArraysBuilding removeObject:self];
- #endif // DEBUG
- // Now copy with our zone.
- realArray_ = [builder copyWithZone:[self zone]];
- }
- // ----------------------------------------------------------------------------
- // NSArray has two methods that everything else seems to work on, simply
- // implement those.
- - (NSUInteger)count {
- if (!realArray_) [self setupRealArray];
- return [realArray_ count];
- }
- - (id)objectAtIndex:(NSUInteger)idx {
- if (!realArray_) [self setupRealArray];
- return [realArray_ objectAtIndex:idx];
- }
- // ----------------------------------------------------------------------------
- // Directly relay the enumeration based calls just in case there is some extra
- // efficency to be had.
- - (NSEnumerator *)objectEnumerator {
- if (!realArray_) [self setupRealArray];
- return [realArray_ objectEnumerator];
- }
- - (NSEnumerator *)reverseObjectEnumerator {
- if (!realArray_) [self setupRealArray];
- return [realArray_ reverseObjectEnumerator];
- }
- #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
- objects:(id *)stackbuf
- count:(NSUInteger)len {
- if (!realArray_) [self setupRealArray];
- return [realArray_ countByEnumeratingWithState:state
- objects:stackbuf
- count:len];
- }
- #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- // ----------------------------------------------------------------------------
- // Directly relay the copy methods, again, for any extra efficency.
- - (id)copyWithZone:(NSZone *)zone {
- if (!realArray_) [self setupRealArray];
- return [realArray_ copyWithZone:zone];
- }
- - (id)mutableCopyWithZone:(NSZone *)zone {
- if (!realArray_) [self setupRealArray];
- return [realArray_ mutableCopyWithZone:zone];
- }
- // ----------------------------------------------------------------------------
- // On 10.6, being loaded out of a nib causes the object to get hashed and
- // stored off. The implementation of -hash in NSArray then calls -count, which
- // causes this object to latch on to an empty array. So...
- // 1. -hash gets overridden to simply use the class pointer to maintain
- // the -[NSObject hash] contract that equal objects must have the same hash
- // value. This puts the work in isEqual...
- // 2. -isEqual: overide. Objects can't use the NSArray version until all of
- // the outlets have been filled in and the object is truly setup. The best
- // escape for this is to simply do pointer comparison until the outlets are
- // fully setup.
- // 3. awakeFromNib gets overridden to force the initialize of the real array
- // when all the outlets have been filled in.
- //
- // NOTE: The first attempt was to just overide hash, but that only makes the
- // first IBArray in a nib work. The fact that isEqual was falling through to
- // the NSArray version (comparing to empty arrays), prevented all of the
- // IBArrays from being fully loaded from the nib correctly.
- - (NSUInteger)hash {
- return (NSUInteger)(void*)[self class];
- }
- - (BOOL)isEqual:(id)anObject {
- if ([anObject isMemberOfClass:[self class]]) {
- GTMIBArray *ibArray2 = anObject;
- if (!realArray_ || !(ibArray2->realArray_)) {
- // If realArray_ or ibArray2 haven't been fully configured yet, the only
- // way they can be equal is if they are the same pointer.
- return (self == anObject);
- }
- }
- return [super isEqual:anObject];
- }
- - (void)awakeFromNib {
- [realArray_ autorelease];
- realArray_ = nil;
- [self setupRealArray];
- }
- @end