/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

  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. #import "GTMIBArray.h"
  19. #import "GTMDefines.h"
  20. @implementation GTMIBArray
  21. - (void)dealloc {
  22. [realArray_ release];
  23. [super dealloc];
  24. }
  25. - (void)setupRealArray {
  26. #ifdef DEBUG
  27. // It is very easy to create a cycle if you are chaining these in IB, so in
  28. // debug builds, we try to catch this to inform the developer. Use -[NSArray
  29. // indexOfObjectIdenticalTo:] to get pointer comparisons instead of object
  30. // equality.
  31. static NSMutableArray *ibArraysBuilding = nil;
  32. if (!ibArraysBuilding) {
  33. ibArraysBuilding = [[NSMutableArray alloc] init];
  34. }
  35. _GTMDevAssert([ibArraysBuilding indexOfObjectIdenticalTo:self] == NSNotFound,
  36. @"There is a cycle in your GTMIBArrays!");
  37. [ibArraysBuilding addObject:self];
  38. #endif // DEBUG
  39. // Build the array up.
  40. NSMutableArray *builder = [NSMutableArray array];
  41. Class ibArrayClass = [GTMIBArray class];
  42. id objs[] = {
  43. object1_, object2_, object3_, object4_, object5_,
  44. };
  45. for (size_t idx = 0 ; idx < sizeof(objs) / (sizeof(objs[0])) ; ++idx) {
  46. id obj = objs[idx];
  47. if (obj) {
  48. if ([obj isKindOfClass:ibArrayClass]) {
  49. [builder addObjectsFromArray:obj];
  50. } else {
  51. [builder addObject:obj];
  52. }
  53. }
  54. }
  55. #ifdef DEBUG
  56. [ibArraysBuilding removeObject:self];
  57. #endif // DEBUG
  58. // Now copy with our zone.
  59. realArray_ = [builder copyWithZone:[self zone]];
  60. }
  61. // ----------------------------------------------------------------------------
  62. // NSArray has two methods that everything else seems to work on, simply
  63. // implement those.
  64. - (NSUInteger)count {
  65. if (!realArray_) [self setupRealArray];
  66. return [realArray_ count];
  67. }
  68. - (id)objectAtIndex:(NSUInteger)idx {
  69. if (!realArray_) [self setupRealArray];
  70. return [realArray_ objectAtIndex:idx];
  71. }
  72. // ----------------------------------------------------------------------------
  73. // Directly relay the enumeration based calls just in case there is some extra
  74. // efficency to be had.
  75. - (NSEnumerator *)objectEnumerator {
  76. if (!realArray_) [self setupRealArray];
  77. return [realArray_ objectEnumerator];
  78. }
  79. - (NSEnumerator *)reverseObjectEnumerator {
  80. if (!realArray_) [self setupRealArray];
  81. return [realArray_ reverseObjectEnumerator];
  82. }
  83. #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
  84. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
  85. objects:(id *)stackbuf
  86. count:(NSUInteger)len {
  87. if (!realArray_) [self setupRealArray];
  88. return [realArray_ countByEnumeratingWithState:state
  89. objects:stackbuf
  90. count:len];
  91. }
  92. #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
  93. // ----------------------------------------------------------------------------
  94. // Directly relay the copy methods, again, for any extra efficency.
  95. - (id)copyWithZone:(NSZone *)zone {
  96. if (!realArray_) [self setupRealArray];
  97. return [realArray_ copyWithZone:zone];
  98. }
  99. - (id)mutableCopyWithZone:(NSZone *)zone {
  100. if (!realArray_) [self setupRealArray];
  101. return [realArray_ mutableCopyWithZone:zone];
  102. }
  103. // ----------------------------------------------------------------------------
  104. // On 10.6, being loaded out of a nib causes the object to get hashed and
  105. // stored off. The implementation of -hash in NSArray then calls -count, which
  106. // causes this object to latch on to an empty array. So...
  107. // 1. -hash gets overridden to simply use the class pointer to maintain
  108. // the -[NSObject hash] contract that equal objects must have the same hash
  109. // value. This puts the work in isEqual...
  110. // 2. -isEqual: overide. Objects can't use the NSArray version until all of
  111. // the outlets have been filled in and the object is truly setup. The best
  112. // escape for this is to simply do pointer comparison until the outlets are
  113. // fully setup.
  114. // 3. awakeFromNib gets overridden to force the initialize of the real array
  115. // when all the outlets have been filled in.
  116. //
  117. // NOTE: The first attempt was to just overide hash, but that only makes the
  118. // first IBArray in a nib work. The fact that isEqual was falling through to
  119. // the NSArray version (comparing to empty arrays), prevented all of the
  120. // IBArrays from being fully loaded from the nib correctly.
  121. - (NSUInteger)hash {
  122. return (NSUInteger)(void*)[self class];
  123. }
  124. - (BOOL)isEqual:(id)anObject {
  125. if ([anObject isMemberOfClass:[self class]]) {
  126. GTMIBArray *ibArray2 = anObject;
  127. if (!realArray_ || !(ibArray2->realArray_)) {
  128. // If realArray_ or ibArray2 haven't been fully configured yet, the only
  129. // way they can be equal is if they are the same pointer.
  130. return (self == anObject);
  131. }
  132. }
  133. return [super isEqual:anObject];
  134. }
  135. - (void)awakeFromNib {
  136. [realArray_ autorelease];
  137. realArray_ = nil;
  138. [self setupRealArray];
  139. }
  140. @end