26 @implementation CPObject (CPArrayKVO)
28 - (id)mutableArrayValueForKey:(
id)aKey
30 return [[_CPKVCArray alloc] initWithKey:aKey forProxyObject:self];
33 - (id)mutableArrayValueForKeyPath:(
id)aKeyPath
35 var dotIndex = aKeyPath.indexOf(
".");
38 return [
self mutableArrayValueForKey:aKeyPath];
40 var firstPart = aKeyPath.substring(0, dotIndex),
41 lastPart = aKeyPath.substring(dotIndex + 1);
43 return [[
self valueForKeyPath:firstPart] mutableArrayValueForKeyPath:lastPart];
69 Function _replaceMany;
71 SEL _objectAtIndexSEL;
72 Function _objectAtIndex;
74 SEL _objectsAtIndexesSEL;
75 Function _objectsAtIndexes;
93 var ivars = class_copyIvarList(
self),
97 array[ivar_getName(ivars[count])] = nil;
102 - (id)initWithKey:(
id)aKey forProxyObject:(
id)anObject
107 _proxyObject = anObject;
109 var capitalizedKey = _key.charAt(0).toUpperCase() + _key.substring(1);
111 _insertSEL = sel_getName(
@"insertObject:in" + capitalizedKey +
"AtIndex:");
113 if ([_proxyObject respondsToSelector:_insertSEL])
114 _insert = [_proxyObject methodForSelector:_insertSEL];
116 _removeSEL = sel_getName(
@"removeObjectFrom" + capitalizedKey +
"AtIndex:");
118 if ([_proxyObject respondsToSelector:_removeSEL])
119 _remove = [_proxyObject methodForSelector:_removeSEL];
121 _replaceSEL = sel_getName(
@"replaceObjectIn" + capitalizedKey +
"AtIndex:withObject:");
123 if ([_proxyObject respondsToSelector:_replaceSEL])
124 _replace = [_proxyObject methodForSelector:_replaceSEL];
126 _insertManySEL = sel_getName(
@"insert" + capitalizedKey +
":atIndexes:");
128 if ([_proxyObject respondsToSelector:_insertManySEL])
129 _insertMany = [_proxyObject methodForSelector:_insertManySEL];
131 _removeManySEL = sel_getName(
@"remove" + capitalizedKey +
"AtIndexes:");
133 if ([_proxyObject respondsToSelector:_removeManySEL])
134 _removeMany = [_proxyObject methodForSelector:_removeManySEL];
136 _replaceManySEL = sel_getName(
@"replace" + capitalizedKey +
"AtIndexes:with" + capitalizedKey +
":");
138 if ([_proxyObject respondsToSelector:_replaceManySEL])
139 _replaceMany = [_proxyObject methodForSelector:_replaceManySEL];
141 _objectAtIndexSEL = sel_getName(
@"objectIn" + capitalizedKey +
"AtIndex:");
143 if ([_proxyObject respondsToSelector:_objectAtIndexSEL])
144 _objectAtIndex = [_proxyObject methodForSelector:_objectAtIndexSEL];
146 _objectsAtIndexesSEL = sel_getName(_key +
"AtIndexes:");
148 if ([_proxyObject respondsToSelector:_objectsAtIndexesSEL])
149 _objectsAtIndexes = [_proxyObject methodForSelector:_objectsAtIndexesSEL];
151 _countSEL = sel_getName(
@"countOf" + capitalizedKey);
153 if ([_proxyObject respondsToSelector:_countSEL])
154 _count = [_proxyObject methodForSelector:_countSEL];
156 _accessSEL = sel_getName(_key);
158 if ([_proxyObject respondsToSelector:_accessSEL])
159 _access = [_proxyObject methodForSelector:_accessSEL];
161 _setSEL = sel_getName(
@"set" + capitalizedKey +
":");
163 if ([_proxyObject respondsToSelector:_setSEL])
164 _set = [_proxyObject methodForSelector:_setSEL];
173 count = [
self count];
175 for (; i < count; i++)
176 [theCopy addObject:[self objectAtIndex:i]];
181 - (id)_representedObject
184 return _access(_proxyObject, _accessSEL);
186 return [_proxyObject valueForKey:_key];
189 - (void)_setRepresentedObject:(
id)anObject
192 return _set(_proxyObject, _setSEL, anObject);
194 [_proxyObject setValue:anObject forKey:_key];
200 return _count(_proxyObject, _countSEL);
202 return [[
self _representedObject] count];
205 - (CPUInteger)indexOfObject:(
id)anObject inRange:(CPRange)aRange
207 var index = aRange.location,
208 count = aRange.length,
209 shouldIsEqual = !!anObject.isa;
211 for (; index < count; ++index)
213 var
object = [
self objectAtIndex:index];
215 if (anObject ===
object || shouldIsEqual && !!
object.
isa && [anObject
isEqual:
object])
222 - (CPUInteger)indexOfObject:(
id)anObject
224 return [
self indexOfObject:anObject inRange:CPMakeRange(0, [
self count])];
227 - (CPUInteger)indexOfObjectIdenticalTo:(
id)anObject inRange:(CPRange)aRange
229 var index = aRange.location,
230 count = aRange.length;
232 for (; index < count; ++index)
233 if (anObject === [self objectAtIndex:index])
239 - (CPUInteger)indexOfObjectIdenticalTo:(
id)anObject
241 return [
self indexOfObjectIdenticalTo:anObject inRange:CPMakeRange(0, [
self count])];
244 - (id)objectAtIndex:(CPUInteger)anIndex
249 - (CPArray)objectsAtIndexes:(
CPIndexSet)theIndexes
251 if (_objectsAtIndexes)
252 return _objectsAtIndexes(_proxyObject, _objectsAtIndexesSEL, theIndexes);
259 while ((index = [theIndexes indexGreaterThanIndex:index]) !==
CPNotFound)
260 objects.push(_objectAtIndex(_proxyObject, _objectAtIndexSEL, index));
265 return [[
self _representedObject] objectsAtIndexes:theIndexes];
268 - (void)addObject:(
id)anObject
270 [
self insertObject:anObject atIndex:[
self count]];
273 - (void)addObjectsFromArray:(CPArray)anArray
276 count = [anArray count];
281 - (void)insertObject:(
id)anObject atIndex:(CPUInteger)anIndex
286 - (void)insertObjects:(CPArray)theObjects atIndexes:(
CPIndexSet)theIndexes
289 _insertMany(_proxyObject, _insertManySEL, theObjects, theIndexes);
292 var indexesArray = [];
295 for (var index = 0; index < [indexesArray count]; index++)
297 var objectIndex = [indexesArray objectAtIndex:index],
298 object = [theObjects objectAtIndex:index];
300 _insert(_proxyObject, _insertSEL,
object, objectIndex);
305 var target = [[
self _representedObject] copy];
307 [target insertObjects:theObjects atIndexes:theIndexes];
308 [
self _setRepresentedObject:target];
312 - (void)removeObject:(
id)anObject
314 [
self removeObject:anObject inRange:CPMakeRange(0, [
self count])];
317 - (void)removeObjectsInArray:(CPArray)theObjects
322 index = [theObjects count],
324 count = [
self count];
328 while ((position = [
self indexOfObject:[theObjects objectAtIndex:index] inRange:
CPMakeRange(position + 1, count)]) !==
CPNotFound)
329 [indexes addIndex:position];
332 _removeMany(_proxyObject, _removeManySEL, indexes);
336 var index = [theObjects count],
340 while ((position = [
self indexOfObject:[theObjects objectAtIndex:index]]) !==
CPNotFound)
341 _remove(_proxyObject, _removeSEL, position);
346 var target = [[
self _representedObject] copy];
347 [target removeObjectsInArray:theObjects];
348 [
self _setRepresentedObject:target];
352 - (void)removeObject:(
id)theObject inRange:(CPRange)theRange
355 _remove(_proxyObject, _removeSEL, [
self indexOfObject:theObject inRange:theRange]);
356 else if (_removeMany)
358 var index = [
self indexOfObject:theObject inRange:theRange];
359 _removeMany(_proxyObject, _removeManySEL, [
CPIndexSet indexSetWithIndex:index]);
365 while ((index = [
self indexOfObject:theObject inRange:theRange]) !==
CPNotFound)
367 [
self removeObjectAtIndex:index];
373 - (void)removeLastObject
378 - (void)removeObjectAtIndex:(CPUInteger)anIndex
383 - (void)removeObjectsAtIndexes:(
CPIndexSet)theIndexes
386 _removeMany(_proxyObject, _removeManySEL, theIndexes);
393 _remove(_proxyObject, _removeSEL, index)
394 index = [theIndexes indexLessThanIndex:index];
399 var target = [[
self _representedObject] copy];
400 [target removeObjectsAtIndexes:theIndexes];
401 [
self _setRepresentedObject:target];
405 - (void)replaceObjectAtIndex:(CPUInteger)anIndex withObject:(
id)anObject
410 - (void)replaceObjectsAtIndexes:(
CPIndexSet)theIndexes withObjects:(CPArray)theObjects
413 return _replaceMany(_proxyObject, _replaceManySEL, theIndexes, theObjects);
421 _replace(_proxyObject, _replaceSEL, index, [theObjects objectAtIndex:i++]);
427 var target = [[
self _representedObject] copy];
428 [target replaceObjectsAtIndexes:theIndexes withObjects:theObjects];
429 [
self _setRepresentedObject:target];
438 @implementation CPArray (CPKeyValueCoding)
442 if (aKey.charAt(0) ===
"@")
444 if (aKey.indexOf(
".") !== -1)
445 [
CPException raise:CPInvalidArgumentException reason:"called valueForKey: on an array with a complex key (" + aKey + "). use valueForKeyPath:"];
447 if (aKey ===
"@count")
450 return [
self valueForUndefinedKey:aKey];
455 enumerator = [
self objectEnumerator],
458 while ((
object = [enumerator nextObject]) !== nil)
460 var value = [object valueForKey:aKey];
462 if (value === nil || value === undefined)
465 newArray.push(value);
472 - (id)valueForKeyPath:(
CPString)aKeyPath
475 [
self valueForUndefinedKey:@"<empty path>"];
477 if (aKeyPath.charAt(0) ===
"@")
479 var dotIndex = aKeyPath.indexOf(
"."),
485 operator = aKeyPath.substring(1, dotIndex);
486 parameter = aKeyPath.substring(dotIndex + 1);
489 operator = aKeyPath.substring(1);
491 return [_CPCollectionKVCOperator performOperation:operator withCollection:self propertyPath:parameter];
496 enumerator = [
self objectEnumerator],
499 while ((
object = [enumerator nextObject]) !== nil)
501 var value = [object valueForKeyPath:aKeyPath];
503 if (value === nil || value === undefined)
506 newArray.push(value);
513 - (void)setValue:(
id)aValue forKey:(
CPString)aKey
515 var enumerator = [
self objectEnumerator],
518 while ((
object = [enumerator nextObject]) !== nil)
519 [object setValue:aValue forKey:aKey];
522 - (void)setValue:(
id)aValue forKeyPath:(
CPString)aKeyPath
524 var enumerator = [
self objectEnumerator],
527 while ((
object = [enumerator nextObject]) !== nil)
528 [object setValue:aValue forKeyPath:aKeyPath];
533 @implementation CPArray (KeyValueObserving)
542 - (void)addObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)anOptions context:(
id)aContext
544 if (aKeyPath !==
@"@count")
545 [
CPException raise:CPInvalidArgumentException
reason:"[CPArray " + CPStringFromSelector(_cmd) + "] is not supported. Key path: " + aKeyPath];
555 - (void)removeObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath
557 if (aKeyPath !==
@"@count")
558 [
CPException raise:CPInvalidArgumentException
reason:"[CPArray " + CPStringFromSelector(_cmd) + "] is not supported. Key path: " + aKeyPath];
564 - (void)addObserver:(
id)anObserver toObjectsAtIndexes:(
CPIndexSet)indexes forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
570 [
self[index] addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
579 - (void)removeObserver:(
id)anObserver fromObjectsAtIndexes:(
CPIndexSet)indexes forKeyPath:(
CPString)aKeyPath
585 [
self[index] removeObserver:anObserver forKeyPath:aKeyPath];