/** * Allocates a new instance of the receiver from the default * zone, by invoking +allocWithZone: with * <code>NSDefaultMallocZone()</code> as the zone argument.<br /> * Returns the created instance. */ + (id) alloc { return [self allocWithZone: NSDefaultMallocZone()]; }
/** * This is the basic method to create a new instance. It * allocates a new instance of the receiver from the specified * memory zone. * <p> * Memory for an instance of the receiver is allocated; a * pointer to this newly created instance is returned. All * instance variables are set to 0. No initialization of the * instance is performed apart from setup to be an instance of * the correct class: it is your responsibility to initialize the * instance by calling an appropriate <code>init</code> * method. If you are not using ARC, it is * also your responsibility to make sure the returned * instance is destroyed when you finish using it, by calling * the <code>release</code> method to destroy the instance * directly, or by using <code>autorelease</code> and * autorelease pools. * </p> * <p> * You do not normally need to override this method in * subclasses, unless you are implementing a class which for * some reasons silently allocates instances of another class * (this is typically needed to implement class clusters and * similar design schemes). * </p> * <p> * If you have turned on debugging of object allocation (by * calling the <code>GSDebugAllocationActive</code> * function), this method will also update the various * debugging counts and monitors of allocated objects, which * you can access using the <code>GSDebugAllocation...</code> * functions. * </p> */ + (id) allocWithZone: (NSZone*)z { returnNSAllocateObject(self, 0, z); }
/* * 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 { NSUInteger retained; NSZone *zone; char padding[ALIGN - ((UNP % ALIGN) ? (UNP % ALIGN) : ALIGN)]; }; typedefstruct obj_layout *obj;
/* * Now do conditional compilation of memory allocation functions * depending on what information (if any) we are storing before * the start of each object. */
// FIXME rewrite object allocation to use class_createInstance when we // are using libobjc2. inlineid NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone) { id new;
#ifdef OBJC_CAP_ARC if ((new = class_createInstance(aClass, extraBytes)) != nil) { AADD(aClass, new); } #else int size; // 容纳对象所需要的大小
NSCAssert((!class_isMetaClass(aClass)), @"Bad class for new object"); // 计算容纳对象所需要的大小 // 实例的大小由三部分构成,类本身的大小、额外的大小、保存引用计数结构体的大小 size = class_getInstanceSize(aClass) + extraBytes + sizeof(struct obj_layout); if (zone == 0) { zone = NSDefaultMallocZone(); } // 调用函数,分配存放对象所需的空间 new = NSZoneMalloc(zone, size); if (new != nil) { // 将该内存空间全部置为0 memset (new, 0, size); new = (id)&((obj)new)[1]; object_setClass(new, aClass); AADD(aClass, new); }
/* Don't bother doing this in a thread-safe way, because the cost of locking * will be a lot more than the cost of doing the same call in two threads. * The returned selector will persist and the runtime will ensure that both * calls return the same selector, so we don't need to bother doing it * ourselves. */ if (0 == cxx_construct) { cxx_construct = sel_registerName(".cxx_construct"); cxx_destruct = sel_registerName(".cxx_destruct"); } callCXXConstructors(aClass, new); #endif
/** * 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.<br /> * By convention, objects which should (or can) never be deallocated * return the maximum unsigned integer value. */ - (NSUInteger) retainCount { #if GS_WITH_GC returnUINT_MAX; #else returnNSExtraRefCount(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).<br /> * The retain count for an object is this value plus one. */ inlineNSUInteger NSExtraRefCount(id anObject) { #if GS_WITH_GC returnUINT_MAX - 1; #else/* GS_WITH_GC */ return ((obj)anObject)[-1].retained; #endif/* GS_WITH_GC */ }
/** * Increments the reference count and returns the receiver.<br /> * The default implementation does this by calling NSIncrementExtraRefCount() */ - (id) retain { #if GS_WITH_GC == 0 NSIncrementExtraRefCount(self); #endif returnself; }
/** * Increments the extra reference count for anObject.<br /> * The GNUstep version raises an exception if the reference count * would be incremented to too large a value.<br /> * This is used by the [NSObject-retain] method. */ inlinevoid NSIncrementExtraRefCount(id anObject) { #if GS_WITH_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"]; } /** * Decrements the retain count for the receiver if greater than zero, * otherwise calls the dealloc method instead.<br /> * 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.<br /> * In GNUstep, the [NSObject+enableDoubleReleaseCheck:] method may be used * to turn on checking for ratain/release errors in this method. */ - (onewayvoid) release { #if GS_WITH_GC == 0 if (NSDecrementExtraRefCountWasZero(self)) { [self dealloc]; } #endif } } #endif/* GS_WITH_GC */ }
/** * Decrements the retain count for the receiver if greater than zero, * otherwise calls the dealloc method instead.<br /> * 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.<br /> * In GNUstep, the [NSObject+enableDoubleReleaseCheck:] method may be used * to turn on checking for ratain/release errors in this method. */ - (onewayvoid) release { #if GS_WITH_GC == 0 if (NSDecrementExtraRefCountWasZero(self)) { [self dealloc]; } #endif }
/** * Examines the extra reference count for the object and, if non-zero * decrements it, otherwise leaves it unchanged.<br /> * Returns a flag to say whether the count was zero * (and hence whether the extra reference count was decremented).<br /> * This function is used by the [NSObject-release] method. */ BOOL NSDecrementExtraRefCountWasZero(id anObject) { #if !GS_WITH_GC if (double_release_check_enabled) { NSUInteger release_count; NSUInteger retain_count = [anObject retainCount]; release_count = [autorelease_class autoreleaseCountForObject: anObject]; if (release_count >= retain_count) [NSException raise: NSGenericException format: @"Release would release object too many times."]; } if (allocationLock != 0) { #if defined(GSATOMICREAD) int result;
result = GSAtomicDecrement((gsatomic_t)&(((obj)anObject)[-1].retained)); if (result < 0) { if (result != -1) { [NSException raise: NSInternalInconsistencyException format: @"NSDecrementExtraRefCount() decremented too far"]; } /* The counter has become negative so it must have been zero. * We reset it and return YES ... in a correctly operating * process we know we can safely reset back to zero without * worrying about atomicity, since there can be no other * thread accessing the object (or its reference count would * have been greater than zero) */ (((obj)anObject)[-1].retained) = 0; returnYES; } #else/* GSATOMICREAD */ NSLock *theLock = GSAllocationLockForObject(anObject);
/** * Deallocates the receiver by calling NSDeallocateObject() with self * as the argument.<br /> * <p> * You should normally call the superclass implementation of this method * when you override it in a subclass, or the memory occupied by your * object will not be released. * </p> * <p> * <code>NSObject</code>'s implementation of this method * destroys the receiver, by returning the memory allocated * to the receiver to the system. After this method has been * called on an instance, you must not refer the instance in * any way, because it does not exist any longer. If you do, * it is a bug and your program might even crash with a * segmentation fault. * </p> * <p> * Normally you are supposed to manage the memory taken by * objects by using the high level interface provided by the * <code>retain</code>, <code>release</code> and * <code>autorelease</code> methods (or better by the * corresponding macros <code>RETAIN</code>, * <code>RELEASE</code> and <code>AUTORELEASE</code>), and by * autorelease pools and such; whenever the * release/autorelease mechanism determines that an object is * no longer needed (which happens when its retain count * reaches 0), it will call the <code>dealloc</code> method * to actually deallocate the object. This means that normally, * you should not need to call <code>dealloc</code> directly as * the gnustep base library automatically calls it for you when * the retain count of an object reaches 0. * </p> * <p> * Because the <code>dealloc</code> method will be called * when an instance is being destroyed, if instances of your * subclass use objects or resources (as it happens for most * useful classes), you must override <code>dealloc</code> in * subclasses to release all objects and resources which are * used by the instance, otherwise these objects and * resources would be leaked. In the subclass * implementation, you should first release all your subclass * specific objects and resources, and then invoke super's * implementation (which will do the same, and so on up in * the class hierarchy to <code>NSObject</code>'s * implementation, which finally destroys the object). Here * is an example of the implementation of * <code>dealloc</code> for a subclass whose instances have a * single instance variable <code>name</code> which needs to * be released when an instance is deallocated: * </p> * <p> * <code> * - (void) dealloc * { * RELEASE (name); * [super dealloc]; * } * </code> * </p> * <p> * <code>dealloc</code> might contain code to release not * only objects, but also other resources, such as open * files, network connections, raw memory allocated in other * ways, etc. * </p> * <p> * 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.<br /> * 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. * </p> */ - (void) dealloc { NSDeallocateObject(self); }
/** * Adds the receiver to the current autorelease pool, so that it will be * sent a -release message when the pool is destroyed.<br /> * Returns the receiver.<br /> * In GNUstep, the [NSObject+enableDoubleReleaseCheck:] method may be used * to turn on checking for retain/release errors in this method. */ - (id) autorelease { // 下面这行代码等价于 [NSAutoreleasePool addObject:self]; // GNUstep为了提高频繁调用autorelease方法的效率,对一些结果值进行了缓存 // 这里的调用直接使用的是缓存的结果,总之提高了2倍的运行速度 (*autorelease_imp)(autorelease_class, autorelease_sel, self);
// 取得正在使用的NSAutoreleasePool // NSAutoreleasePool对象可以嵌套生成,这里会理所当然地获取最里面一层的对象 pool = t->_autorelease_vars.current_pool; if (pool == nil && t->_active == NO) { // Don't leak while exiting thread. pool = t->_autorelease_vars.current_pool = [self new]; } if (pool != nil) { // 调用正在使用的NSAutoreleasePool对象的addObject方法 (*pool->_addImp)(pool, @selector(addObject:), anObj); } else { NSAutoreleasePool *arp = [NSAutoreleasePool new];
if (anObj != nil) { NSLog(@"autorelease called without pool for object (%p) " @"of class %@ in thread %@", anObj, NSStringFromClass([anObj class]), [NSThread currentThread]); } else { NSLog(@"autorelease called without pool for nil object."); } [arp release]; } }
/* Remove self from the linked list of pools in use. * We already know that we have deallocated any child (in -emptyPool), * but we may have a parent which needs to know we have gone. * The only other place where the parent/child linked list is modified * should be in -init */ // 但是我们还要通知父节点 if (tv->current_pool == self) { tv->current_pool = _parent; } if (_parent != nil) { _parent->_child = nil; _parent = nil; }
/* Don't deallocate ourself, just save us for later use. */ push_pool_to_cache (tv, self); GSNOSUPERDEALLOC; }
@autoreleasepool { id __autoreleasing obj = [[NSObject alloc] init]; }
// 等价于
id pool = objc_autoreleasePoolPush(); id obj = objc_msgSend(NSObject,@selector(alloc)); objc_msgSend(obj,@selector(init)); objc_autorelease(obj); objc_autoreleasePoolPop(pool);
// -----
@autoreleasepool { id __autoreleasing obj = [NSMutableArray array]; }
// 等价于 id pool = objc_autoreleasePoolPush(); id obj = objc_msgSend(NSObject,@selector(array)); // 持有对象的方法发生了改变 objc_retainAutoreleaseReturnValue(obj); objc_autorelease(obj); objc_autoreleasePoolPop(pool);