//自己生成並持有對象 id obj = [[NSObject alloc] init]; //自己持有對象 [obj release]; //對象已釋放 [obj release]; //釋放之後再次釋放已非自己持有的對象,應用程序崩潰。 //崩潰情況: 再度廢棄已經廢棄了的對象時崩潰, 訪問已經廢棄的對象時崩潰 我們取得對象,但是自己不持有對象: //取得對象,但是自己並不持有對象 id obj1 = [obj0 object]; //釋放不是自己持有的對象,應用程序崩潰 [obj1 release];
/**
* Allocates a new instance of the receiver from the default
* zone, by invoking +allocWithZone: with
* NSDefaultMallocZone()
as the zone argument.
* Returns the created instance.
*/
+ (id) alloc
{
return [self allocWithZone: NSDefaultMallocZone()];
}
*
* If you have turned on debugging of object allocation (by * calling the GSDebugAllocationActive
* function), this method will also update the various * debugging counts and monitors of allocated objects, which * you can access using the GSDebugAllocation...
* functions. *
/* * Now do the REAL version - using the other version to determine * what padding (if any) is required to get the alignment of the * structure correct. */ struct obj_layout { char padding[__BIGGEST_ALIGNMENT__ - ((UNP % __BIGGEST_ALIGNMENT__) ? (UNP % __BIGGEST_ALIGNMENT__) : __BIGGEST_ALIGNMENT__)]; NSUInteger retained; }; inline id NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) { int size = 計算容納對象所需內存大小. id new = NSZoneMalloc(zone, size); memset(new, 0, size); new = (id) & ((struct obj_layout *)new)[1]; }
struct obj_layout { NSUInteger retained; }; + (id) alloc { int size = sizeof (struct obj_layout) + 對象大小; struct obj_layout *p = (struct obj_alyout*)calloc(1, size); return (id)(p + 1); }
/** * Returns the reference count for the receiver. Each instance has an * implicit reference count of 1, and has an 'extra reference count' * returned by the NSExtraRefCount() function, so the value returned by * this method is always greater than zero. * By convention, objects which should (or can) never be deallocated * return the maximum unsigned integer value. */ - (NSUInteger) retainCount { #if GS_WITH_GC return UINT_MAX; #else return NSExtraRefCount(self) + 1; #endif } /** * Return the extra reference count of anObject (a value in the range * from 0 to the maximum unsigned integer value minus one). * The retain count for an object is this value plus one. */ inline NSUInteger NSExtraRefCount(id anObject) { #ifdef __OBJC_GC__ if (objc_collecting_enabled()) { return UINT_MAX-1; } #endif #if GS_WITH_GC return UINT_MAX - 1; #else /* GS_WITH_GC */ return ((obj)anObject)[-1].retained; #endif /* GS_WITH_GC */ }
retain方法: /** * Increments the reference count and returns the receiver. * The default implementation does this by calling NSIncrementExtraRefCount() */ - (id) retain { #if (GS_WITH_GC == 0) NSIncrementExtraRefCount(self); #endif return self; } /** * Increments the extra reference count for anObject. * The GNUstep version raises an exception if the reference count * would be incremented to too large a value. * This is used by the [NSObject-retain] method. */ inline void NSIncrementExtraRefCount(id anObject) #endif { #if GS_WITH_GC || __OBJC_GC__ return; #else /* GS_WITH_GC */ if (allocationLock != 0) { #if defined(GSATOMICREAD) /* I've seen comments saying that some platforms only support up to * 24 bits in atomic locking, so raise an exception if we try to * go beyond 0xfffffe. */ if (GSAtomicIncrement((gsatomic_t)&(((obj)anObject)[-1].retained)) > 0xfffffe) { [NSException raise: NSInternalInconsistencyException format: @"NSIncrementExtraRefCount() asked to increment too far"]; } #else /* GSATOMICREAD */ NSLock *theLock = GSAllocationLockForObject(anObject); [theLock lock]; if (((obj)anObject)[-1].retained == UINT_MAX - 1) { [theLock unlock]; [NSException raise: NSInternalInconsistencyException format: @"NSIncrementExtraRefCount() asked to increment too far"]; } ((obj)anObject)[-1].retained++; [theLock unlock]; #endif /* GSATOMICREAD */ } else { if (((obj)anObject)[-1].retained == UINT_MAX - 1) { [NSException raise: NSInternalInconsistencyException format: @"NSIncrementExtraRefCount() asked to increment too far"]; } ((obj)anObject)[-1].retained++; } #endif /* GS_WITH_GC */ }
/** * Decrements the retain count for the receiver if greater than zero, * otherwise calls the dealloc method instead. * The default implementation calls the NSDecrementExtraRefCountWasZero() * function to test the extra reference count for the receiver (and * decrement it if non-zero) - if the extra reference count is zero then * the retain count is one, and the dealloc method is called. * In GNUstep, the [NSObject+enableDoubleReleaseCheck:] method may be used * to turn on checking for ratain/release errors in this method. */ - (oneway void) release { #if (GS_WITH_GC == 0) if (NSDecrementExtraRefCountWasZero(self)) { # ifdef OBJC_CAP_ARC objc_delete_weak_refs(self); # endif [self dealloc]; } #endif } BOOL NSDecrementExtraRefCountWasZero(id anObject) { if (((struct obj_layout *)anObject)[-1].retained == 0) { return YES; } else { ((struct obj_layout *)anObject)[-1].retained--; return NO; } }
*
* If you have allocated the memory using a non-standard mechanism, you * will not call the superclass (NSObject) implementation of the method * as you will need to handle the deallocation specially.
* In some circumstances, an object may wish to prevent itself from * being deallocated, it can do this simply be refraining from calling * the superclass implementation. *
int __CFDoExternRefOperation(uintptr_t op, id obj) { CFBasicHashRef table = init; int count; switch (op) { case OPERATION_retainCount; count = CFBasicHashGetCountOfKey(table, obj); return count; case OPERATION_retain: CFBasicHashAddValue(table, obj); return obj; case OPERATION_release: count = CFBasicHashRemoveValue(table, obj); return 0 == count; } } - (NSUInteger)retainCount { return (NSUInteger) __CFDoExternRefOperation(OPERATION_retainCount, self); } - (id)retain { return (id)__CFDoExternRefOperation(OPERATION_retain, self); } - (void)release { return __CFDoExternRefOperation(OPERATION_release, self); }
for (int i = 0; i < count; ++i) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; *** [pool drain]; }
- (id) autorelease { [NSAutoreleasePool addObject:self]; }
class AutoreleasePoolPage { static inline void *push() { 生成或持有NSAutoreleasePool類對象。 } static inline void *pop(void *token) { 廢棄NSAutoreleasePool類對象; releaseAll(); } static inline id autorelease(id obj) { 相當於NSAutoreleasePool類的addObject類方法。 } id *add(id obj) { 追加; } void releaseAll() { 調用內部數組中的對象的release實例方法。 } } void *objc_autoreleasePoolPush(void) { return AutoreleasePoolPage::push(); } void objc_autoreleasePoolPop(void *ctxt) { AutoreleasePoolPage:pop(ctxt); } id *obj_autorelease( id obj) { return AutoreleasePoolPage::autorelease(obj); }
id autorelease_class [NSAutoreleasePool class]; SEL autorelease_sel = @selector(addObject:); IMP autorelease_imp = [autorelease_class methodForSelector:autorelease_sel]; 實際: - (id)autorelease { (*autorelease_imp)(autorelease_class, autorelease_sel, self); } 與 - (id)autorelease { [NSAutoreleasePool addObject:self]; }作用相同,但是第一種方法運行效率會快2倍。 但是他依賴於運行環境。