Question
In my ARC project, I have a class that manages objects called LazyMutableArray. Some of the objects are actually zero, but users in my collection will never know about it; so I made it a subclass NSMutableArray, and it tries to do the same. "In particular, objects are saved when added .
Now let's look at the memory behavior of other methods. It turns out that the destruction methods documented by Apple are an exception to this rule, in which they release, not the auto-implemented object.NSArray
There is some debate that Apple cannot automatically destroy the addObject:+ objectAtIndex:+ combination of destroying the array, or it just happens in the tested examples, and in the example that includes Apple.
How can I create in my subclass a method with the same memory semantics?
Last update
After some thought, I decided that the implementation based on is NSMutableArraymore suitable in this case compared to NSPointerArray. The new class, I should note, has the same pair retain/ autoreleaseas the previous implementation.
Thanks to Rob Napier, I see that no modification of my method objectAtIndex:will change this behavior, which answers my initial question about this method.
, retain/autorelease ; , , . .
( NSMutableArray) GitHub: , , test ( -testLazyMutableMemorySemantics).
.
NSMutableArray:
, , . ( , OData), . , , NSArray. .
OData " ", NSArray . , 1000 () 20, . , .
,
I unit test , , .. . , , .
? , lazy, , (* . *). weakSingleton, , 1. :
XCTAssertEqual(weakSingleton, lazy[0], @"Correct element storage");
, 2. , -retainCount ,
lazy[0] = nil;
XCTAssertNil(weakSingleton, @"Dropped by lazy array");
, , weakSingleton .
, , , , β @autorelease B weakSingleton. , , , NSPointerArray -addPointer: (, , ARC [[object retain] autorelease]). !
, overriding, NSMutableArray -objectAtIndex: `, ; , , , , Apple. , : A, /. , :)
1. ARC , ARC Objective-C. ARC.
2 ? , , , B, unit test C.
, [LazyMutableArray -objectAtIndex] , , 0, , , .
3 , , ; , , .
@implementation LazyMutableArray {
NSPointerArray *_objects;
}
- (id)objectAtIndex:(NSUInteger)index {
@synchronized(self) {
if (index >= self.count) {
return nil;
}
__weak id object = [_objects pointerAtIndex:index];
if (object) {
return object;
}
}
[self.delegate array:self missingObjectAtIndex:index];
@synchronized(self) {
if (index >= self.count) {
return nil;
}
__weak id object = [_objects pointerAtIndex:index];
if (object) {
return object;
}
}
@throw([NSException exceptionWithName:NSObjectNotAvailableException
reason:@"Delegate was not able to provide a non-nil element to a lazy array"
userInfo:nil]);
}
- (void)createObjects {
if (!_objects) {
_objects = [NSPointerArray strongObjectsPointerArray];
}
}
- (void)addObject:(id)anObject {
[self createObjects];
[_objects addPointer:(__bridge void*)anObject];
}
:
NSMutableArray * lazy = [LazyMutableArray new];
id singleton = [NSMutableArray new];
[lazy addObject:singleton];
__weak id weakSingleton = singleton;
singleton = [NSMutableDictionary new];
[lazy addObject:singleton];
XCTAssertNotNil(weakSingleton, @"Held by lazy array");
XCTAssertTrue(lazy.count == 2, @"Cleaning and adding objects");
XCTAssertEqual(weakSingleton, lazy[0], @"Correct element storage");
XCTAssertEqual(singleton, lazy[1], @"Correct element storage");
lazy = nil;
XCTAssertNotNil(singleton, @"Not dropped by lazy array");
XCTAssertNil(weakSingleton, @"Dropped by lazy array");
, lazy = [NSMutableArray new] , @autoreleasepool.