PageRenderTime 48ms CodeModel.GetById 9ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/core/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
  1//
  2//  GTMIBArray.m
  3//
  4//  Copyright 2009 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9//
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11//
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19
 20#import "GTMIBArray.h"
 21#import "GTMDefines.h"
 22
 23@implementation GTMIBArray
 24
 25- (void)dealloc {
 26  [realArray_ release];
 27  [super dealloc];
 28}
 29
 30- (void)setupRealArray {
 31
 32#ifdef DEBUG
 33  // It is very easy to create a cycle if you are chaining these in IB, so in
 34  // debug builds, we try to catch this to inform the developer.  Use -[NSArray
 35  // indexOfObjectIdenticalTo:] to get pointer comparisons instead of object
 36  // equality.
 37  static NSMutableArray *ibArraysBuilding = nil;
 38  if (!ibArraysBuilding) {
 39    ibArraysBuilding = [[NSMutableArray alloc] init];
 40  }
 41  _GTMDevAssert([ibArraysBuilding indexOfObjectIdenticalTo:self] == NSNotFound,
 42                @"There is a cycle in your GTMIBArrays!");
 43  [ibArraysBuilding addObject:self];
 44#endif  // DEBUG
 45
 46  // Build the array up.
 47  NSMutableArray *builder = [NSMutableArray array];
 48  Class ibArrayClass = [GTMIBArray class];
 49  id objs[] = {
 50    object1_, object2_, object3_, object4_, object5_,
 51  };
 52  for (size_t idx = 0 ; idx < sizeof(objs) / (sizeof(objs[0])) ; ++idx) {
 53    id obj = objs[idx];
 54    if (obj) {
 55      if ([obj isKindOfClass:ibArrayClass]) {
 56        [builder addObjectsFromArray:obj];
 57      } else {
 58        [builder addObject:obj];
 59      }
 60    }
 61  }
 62
 63#ifdef DEBUG
 64  [ibArraysBuilding removeObject:self];
 65#endif  // DEBUG
 66
 67  // Now copy with our zone.
 68  realArray_ = [builder copyWithZone:[self zone]];
 69}
 70
 71// ----------------------------------------------------------------------------
 72// NSArray has two methods that everything else seems to work on, simply
 73// implement those.
 74
 75- (NSUInteger)count {
 76  if (!realArray_) [self setupRealArray];
 77  return [realArray_ count];
 78}
 79
 80- (id)objectAtIndex:(NSUInteger)idx {
 81  if (!realArray_) [self setupRealArray];
 82  return [realArray_ objectAtIndex:idx];
 83}
 84
 85// ----------------------------------------------------------------------------
 86// Directly relay the enumeration based calls just in case there is some extra
 87// efficency to be had.
 88
 89- (NSEnumerator *)objectEnumerator {
 90  if (!realArray_) [self setupRealArray];
 91  return [realArray_ objectEnumerator];
 92}
 93
 94- (NSEnumerator *)reverseObjectEnumerator {
 95  if (!realArray_) [self setupRealArray];
 96  return [realArray_ reverseObjectEnumerator];
 97}
 98
 99#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
100
101- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
102                                  objects:(id *)stackbuf
103                                    count:(NSUInteger)len {
104  if (!realArray_) [self setupRealArray];
105  return [realArray_ countByEnumeratingWithState:state
106                                         objects:stackbuf
107                                           count:len];
108}
109
110#endif  // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
111
112// ----------------------------------------------------------------------------
113// Directly relay the copy methods, again, for any extra efficency.
114
115- (id)copyWithZone:(NSZone *)zone {
116  if (!realArray_) [self setupRealArray];
117  return [realArray_ copyWithZone:zone];
118}
119
120- (id)mutableCopyWithZone:(NSZone *)zone {
121  if (!realArray_) [self setupRealArray];
122  return [realArray_ mutableCopyWithZone:zone];
123}
124
125// ----------------------------------------------------------------------------
126// On 10.6, being loaded out of a nib causes the object to get hashed and
127// stored off.  The implementation of -hash in NSArray then calls -count, which
128// causes this object to latch on to an empty array.  So...
129// 1. -hash gets overridden to simply use the class pointer to maintain
130//    the -[NSObject hash] contract that equal objects must have the same hash
131//    value.  This puts the work in isEqual...
132// 2. -isEqual: overide.  Objects can't use the NSArray version until all of
133//    the outlets have been filled in and the object is truly setup. The best
134//    escape for this is to simply do pointer comparison until the outlets are
135//    fully setup.
136// 3. awakeFromNib gets overridden to force the initialize of the real array
137//    when all the outlets have been filled in.
138//
139// NOTE: The first attempt was to just overide hash, but that only makes the
140// first IBArray in a nib work. The fact that isEqual was falling through to
141// the NSArray version (comparing to empty arrays), prevented all of the
142// IBArrays from being fully loaded from the nib correctly.
143
144- (NSUInteger)hash {
145  return (NSUInteger)(void*)[self class];
146}
147
148- (BOOL)isEqual:(id)anObject {
149  if ([anObject isMemberOfClass:[self class]]) {
150    GTMIBArray *ibArray2 = anObject;
151    if (!realArray_ || !(ibArray2->realArray_)) {
152      // If realArray_ or ibArray2 haven't been fully configured yet, the only
153      // way they can be equal is if they are the same pointer.
154      return (self == anObject);
155    }
156  }
157  return [super isEqual:anObject];
158}
159
160- (void)awakeFromNib {
161  [realArray_ autorelease];
162  realArray_ = nil;
163  [self setupRealArray];
164}
165
166@end