Memory Management(means Reference Counting in OC) : a programmer allocates a memory area when the program needs it and frees it when the program no longer needs it.
Reference Counting: invented by George E. Collins in 1960
With Reference Counting,you don't need to remember the value of the reference counter itself or what refers to the object
Exploring Memory Management Further
Reference Counting Rules:
You have ownership of any objects you create.
You can take ownership of an object using retain.
When no longer needed, you must relinquish ownership of an object you own.
You must not relinquish ownership of an object you don’t own.
Action for Objective-C Object
Objective-C Method
Create and have ownership of it
alloc/new/copy/mutableCopy group
Take ownership of it
retain
Relinquish it
release
Dispose of it
dealloc
these method(alloc, retain, release, and dealloc) are not provided by the Objective-C language itself.They are features of the Foundation Framework as part of Cocoa Framework
You Have Ownership of Any Objects You Create
// You create an object and have ownership.
id obj = [[NSObject alloc] init];
id obj = [NSObject new];
id objNew1 = [obj copy];//NSCopying protocol:copyWithZone:
id objNew2 = [obj mutableCopy];//NSMutableCopying protocol:mutableCopyWithZone:
//the naming convention is applied to:
allocMyObject newThatObject copyThis mutableCopyYourObject
//the naming convention is not applied to:
allocate newer copying mutableCopyed
You Can Take Ownership of an Object Using retain
Sometimes methods that are not in the alloc/new/copy/mutableCopy method group return an object : you haven't create it, so you don't have ownership of it.
// Obtain an object without creating it yourself or having ownership
id obj = [NSMutableArray array];
// The obtained object exists and you don’t have ownership of it,but you have a reference to NSMutableArray object.
[obj retain];
// The obtained object exists and you don’t have ownership of it.
When No Longer Needed, You Must Relinquish Ownership of an Object You Own
// 1.alloc -> relinquish
// You create an object and have ownership.
id obj = [[NSObject alloc] init];
// Now you have ownership of the object.
[obj release];
// The object is relinquished.Though the variable obj has the pointer to the object,you can’t access the object anymore.
// 2.retain -> relinquish
// Obtain an object without creating it yourself or having ownership
id obj = [NSMutableArray array];
// The obtained object exists and you don’t have ownership of it.
[obj retain];
// Now you have ownership of the object.
[obj release];
// The object is relinquished.You can’t access the object anymore.
how a method return a created object?
alloc/new/copy/muteableCopy : If a method returns an object of which the methodhasownership,ownership is passed to the caller
- (id)allocObject {
// You create an object and have ownership.
id obj = [[NSObject alloc] init];
// At this moment, this method has ownership of the object.
return obj;
}
[NSMutableArray array] : Returning a New Object Without Ownership.By calling autorelease, you can return the created object without ownership 可以返回,而不是为什么要返回没有ownership的(means by design)
- (id)object {
id obj = [[NSObject alloc] init];
/* At this moment, this method has ownership of the object. */
[obj autorelease];
/* The object exists, and you don’t have ownership of it. */
return obj;
}
You Must Not Relinquish Ownership of an Object You Don’t Own
id obj = [[NSObject alloc] init];
[obj release];
[obj release];//crash
id obj1 = [obj0 object];
[obj1 release];//crash sooner or later
/** why retainCount = -1 ? */
id obj2 = [NSArray array];
NSLog(@"%ld",[obj2 retainCount]);
id obj4 = [NSString string];
NSLog(@"%ld",[obj4 retainCount]);
Implementing alloc, retain, release, and dealloc
Although opensourced, I think this guess procedure still worth of being read so HERE WE GO.
But still, without having the implementation of NSObject itself, it is hard to see the whole picture : NSObject has been opensource
CFFoundation is open-source,and the source code for memory management that is used from NSObject is public
GNUstep is a free software implementation of the Cocoa (formerly OpenStep) Objective-C frameworks, widget toolkit, and application development tools for Unix-like operating systems and Microsoft Windows. It is part of the GNU Project.Although we can’t expect it to be exactly the same as Apple’s implementation, it works in the same manner and the implementation should be similar.Understanding GNUstep source code helps us guess Apple’s Cocoa implementation
class AutoreleasePoolPage {
static inline void *push() {
/* It corresponds to creation and ownership of an NSAutoreleasePool object */
}
static inline void pop(void *token) {
/* It corresponds to disposal of an NSAutoreleasePool object */
releaseAll();
}
static inline id autorelease(id obj) {
/* It corresponds to NSAutoreleasePool class method addObject. */
AutoreleasePoolPage *autoreleasePoolPage = /* getting active AutoreleasePoolPage object */
autoreleasePoolPage->add(obj);
}
id *add(id obj) {
/* add the obj to an internal array; */ }
void releaseAll() {
/* calls release for all the objects in the internal array */
}
};
void *objc_autoreleasePoolPush(void) {
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt) {
AutoreleasePoolPage::pop(ctxt);
}
id objc_autorelease(id obj) {
return AutoreleasePoolPage::autorelease(obj);
}
Chapter2 ARC Rules
Apple: Automatic Reference Counting (ARC) in Objective-C makes memory management the job of the compiler. By enabling ARC with the new Apple LLVM compiler, you will never need to type retain or release again, dramatically simplifying the development process, while reducing crashes and memory leaks. The compiler has a complete understanding of your objects, and releases each object the instant it is no longer used, so apps run as fast as ever, with predictable, smooth performance.1
- the relationship of the reference counting rules with ARC
- the ownership specifiers one by one
- we learn the rules to make your code ARC-friendly: by simply following the rules
Ownership qualifiers
With ARC,, ‘id’ and object type variables must have one of the following four ownership qualifiers:
/* non-ARC */
{
id obj = [[NSObject alloc] init];
[obj release];
}
/* ARC */
{
id __strong obj = [[NSObject alloc] init];
}
{
id __strong obj = [NSMutableArray array];
}
//ownership is properly managed not only by variable scope, but also by assignments between variables
id __strong obj0 = [[NSObject alloc] init];
id __strong obj1 = [[NSObject alloc] init];
id __strong obj2 = nil;
obj0 = obj1;
obj2 = obj0;
obj1 = nil;
obj0 = nil;
obj2 = nil;
//By the way, any variables that are qualified with __strong, __weak, and __autoreleasing, are initialized with nil
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
The above source code is equivalent to the following.
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
2.__weak ownership qualifier
solve circular reference,self reference: A weak reference does not have ownership of the object.
When a variable has a reference to an object and the object is discarded, the weak reference also disappears automatically, which means that the variable is assigned to nil.
id __weak obj = [[NSObject alloc] init];//wrong,
//warning: assigning retained obj to weak variable; obj will be released after assignment [-Warc-unsafe-retained-assign]
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
3.__unsafe_unretained ownership qualifier
__weak : iOS5 (or later) or OSX Lion (or later)
__unsafe _unretained : before iOS5 or before OSX Lion
//__weak和__unsafe_unretained的区别在于:后者不会在对象无ownership之后自动置为nil
id __unsafe_unretained obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);//Crash:野指针,访问僵尸对象,报EXC_BAD_ADDRESS
FYI:
(1)野指针
①C语言:定义了一个指针变量,但是并没有赋初值,它随机指向一个东西
②Obj某指针变量指向的内存空间被释放掉了(指向僵尸对象的指针)
(2)僵尸对象
已经被销毁的对象(无法被使用的对象)
(3)空指针
没有指向存储空间的指针(里面存的是nil,也就是0)
给空指针发消息是没有任何反应的,不会提示出错
(4) EXC_BAD_ADDRESS ARC什么时候会出现?? Core-Foundation,混编,C++
4.__autoreleasing ownership qualifier
①When an object is returned from a method, the compiler checks if the method begins with alloc/new/copy/mutableCopy, and if not, the returned object is automatically registered to the autorelease pool
②Exceptionally, any method whose name begins with init, doesn’t register the return value to autoreleasepool
@autoreleasepool {
//not in the alloc/new/copy/mutableCopy method group,register in autoReleasePool
id __strong obj = [NSMutableArray array];
}
//“id obj” does not have a qualifier. So it is qualified with __strong. When the “return” sentence is executed, the variable scope is left and the strong reference disappears. Therefore the object will be released automatically. Before that, if the compiler detects that the object will be passed to the caller, the object is registered in autoreleasepool.
+ (id) array {
id obj = [[NSMutableArray alloc] init];
return obj;
}
③the weak ownership qualifier is used to avoid cyclic reference. When a variable with a weak qualifier is used, the object is always registered in autoreleasepool.
Why does the object need to be registered in autoreleasepool in order to use the object via the weak qualified variable? Because a variable, which is qualified with weak,
does not have a strong reference, the object might be disposed of at any point. If the object is registered in autoreleasepool, until @autoreleasepool block is left, the object must exist. So, to use the objects via __weak variable safely, the object is registered in autoreleasepool automatically.(to be proved)
④ Any pointers to ‘id’ or object types are qualified with __autoreleasing as default.
id obj == id __strong obj;
id *obj == id __autoreleasing *obj;
NSObject **obj == NSObject * __autoreleasing *obj
-(BOOL) performOperationWithError:(NSError * __autoreleasing *)error;
5.Returning a Result as the Argument
The caller will obtain the object as an argument, which means that the caller does not obtain it from the alloc/new/copy/mutableCopy method group. To follow the memory management rules, when you do not obtain an object by the alloc/new/copy/mutableCopy method group, the object has to be passed without ownership. By the __autoreleasing ownership qualifier, the rule is fulfilled.
- (BOOL) performOperationWithError:(NSError * __autoreleasing *)error {
/* Error occurred. Set errorCode */
return NO;
}
//To assign an object pointer, both ownership qualifiers have to be the same.
NSError __autoreleasing *error = nil;
NSError * __autoreleasing *pError = &error; /* No compile error */
//compile optimization(before)
NSError __strong *error = nil;
BOOL result = [obj performOperationWithError:&error];
//compile optimization(after)
NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
BOOL result = [obj performOperationWithError:&tmp];
error = tmp;
Rules
1.Forget about using retain, release, retainCount, and autorelease.
2.Forget about using NSAllocateObject and NSDeallocateObject.
3.Follow the naming rule for methods related to object creation:
create ownership:alloc/new/copy/mutableCopy/- (instanceType)initWithXXX
4.Forget about calling dealloc explicitly.
dealloc is a suitable place to remove the object from delegate or observers
5.Use @autoreleasepool instead of NSAutoreleasePool.
6.Forget about using Zone (NSZone)
现在CPU的负载能力不需要NSZone这种会带来碎片化的机制
7.Object type variables can’t be members of struct or union in C language.
8.‘id’ and ‘void’ have to be cast explicitly.
With ARC,To cast between ‘id’ or object types and 'void',you can use __bridge
//dangerous: should be careful,since you don't know whether p have ownership or not.
id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
id o = (__bridge id)p;
//__bridge dangling pointer example
void *p = nil;
{
id obj = [NSObject new];
p = (__bridge void *)obj;
}
NSLog(@"%@",(__bridge id)p);//错误,野指针
//__bridge_retained:__bridge_retained cast works as if the assigned variable has ownership of the object
//example 1
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;//pointer p也有ownership
//example 2
void *p = 0;
{
id obj = [[NSObject alloc] init];
p = (__bridge_retained void *)obj;
}
NSLog(@"class=%@", [(__bridge id)p class]);//after leave the scrope variable, p still have ownership
//__bridge_transfer:__bridge_transfer cast will release the object just after the assignment is done.
//example 1
id obj = (__bridge_transfer id)p;
//example 2
void *p = (__bridge_retained void *)[[NSObject alloc] init];
NSLog(@"class=%@", [(__bridge id)p class]);
(void)(__bridge_transfer id)p;
OBJECTIVE-C OBJECT AND CORE FOUNDATION OBJECT
1.Core Foundation,mainly written in C;has reference counting
2.Toll-Free Bridged Types:There are a number of data types in the Core Foundation framework and the Foundation framework that can be used interchangeably. Data types that can be used interchangeably are also referred to as toll-free bridged data types
CFMutableArrayRef cfObject = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
printf("retain count = %d\n", CFGetRetainCount(cfObject));
id obj = CFBridgingRelease(cfObject);
printf("retain count after the cast = %d\n",CFGetRetainCount(cfObject));
NSLog(@"class=%@", obj);
Property
Property modifier
Ownership qualifier
assign
__unsafe _unretained
copy
__strong (note: new copied object is assigned.)
retain
__strong
strong
__strong
unsafe_unretained
__unsafe _unretained
weak
__weak
Chapter 3 ARC implementation
__strong
{
id __strong obj = [[NSObject alloc] init];
}
/* pseudo code by the compiler */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
an object is not obtained by the alloc/new/copy/mutableCopy
objc_retainAutoreleasedReturnValue:
objc_retainAutoreleasedReturnValue function is for performance optimization. It is inserted because the NSMutableArray class method array is not in the alloc/new/copy/mutableCopy method group. The compiler inserts this function every time just after the invocation of a method if the method is not in the group. As the name suggests, it retains an object returned from a method or function after the object is added in autorelease pool.
objc_retainAutoreleasedReturnValue function expects that an objc_autoreleaseReturnValue function has been called inside the method. Any methods, that are not in the alloc/new/copy/mutableCopy group, have to call objc_autoreleaseReturnValue
{
id __strong obj = [NSMutableArray array];
}
/* pseudo code by the compiler */
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
objc_autoreleaseReturnValue
objc_autoreleaseReturnValue adds an object to autorelease pool and returns it
objc_autoreleaseReturnValue checks the caller’s executable code and if the code calls objc_retainAutoreleasedReturnValue just after calling this method: it just returns the object to the caller,So, performance will be improved.
+ (id) array {
return [[NSMutableArray alloc] init];
}
This source code is converted as follows. It calls objc_autoreleaseReturnValue function at the last.
/* pseudo code by the compiler */
+ (id) array
{
id obj = objc_msgSend(NSMutableArray, @selector(alloc));
objc_msgSend(obj, @selector(init));
return objc_autoreleaseReturnValue(obj);
}
__weak
Nil is assigned to any variables qualified with __weak when referencing object is discarded.
When an object is accessed through a __weak qualified variable, the object is added to the autorelease pool: wrong guide
/* example */
{
id __weak obj1 = obj;
}
/* pseudo code by the compiler */
id obj1;
objc_initWeak(&obj1, obj); //call obj1 = 0; objc_storeWeak(&obj1, obj);
objc_destroyWeak(&obj1); //call objc_storeWeak(&obj1, 0);
/**
* This function stores a new value into a __weak variable. It would
* be used anywhere a __weak variable is the target of an assignment.
*
* @param location The address of the weak pointer itself
* @param newObj The new object this weak ptr should now point to
*
* @return \e newObj
*/
id objc_storeWeak(id *location, id newObj)
//when obj = 0,the entry remove from hash table
objc_storeWeak(&obj1, obj);
When an Object Is Discarded
objc_release.
dealloc is called because retain count becomes zero.
_objc_rootDealloc.
object_dispose.
objc_destructInstance.
objc_clear_deallocating:
From the weak table, get an entry of which the key is the object to be discarded.
Set nil to all the __weak ownership qualified variables in the entry.
Remove the entry from the table.
For the object to be disposed of, remove its key from the reference table.
Assigning a Newly Created Object
{
id __weak obj = [[NSObject alloc] init];
}
/* pseudo code by the compiler */
id obj;
id tmp = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(tmp, @selector(init));
objc_initWeak(&obj, tmp);
objc_release(tmp);
objc_destroyWeak(&object);
Adding to autorelease pool Automatically
验证汇编代码: Xcode → Debug → Debug workflow → Always show Disassembly.
输入下面的例子,会看到编译器插入的是release不是autorelease
In conclusion, this design of weak ensure that during the usage of weak pointer, its state is consistent. The new implmenetation of weak of Apple LLVM version 8.0.0 (clang-800.0.42.1) do not postpond the release to autoreleasepool, but use objc_releasedirectly.
{
id __weak obj1 = obj;
NSLog(@"%@", obj1);
}
/* iOS5及之前编译器做法 */
id obj1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);//错误!!!mistake
NSLog(@"%@", tmp);
objc_destroyWeak(&obj1);
/* 现在的编译器做法*/
id obj = objc_msgSend(NSObject, "new");
id obj1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(obj1);//objc_loadWeakRetained would increment the reference count to ensure that tmp is alive in the NSLog statement.
NSLog(@"%@", obj1);
objc_release(tmp);
objc_destroyWeak(&obj1);
objc_storeStrong(&obj, 0);//release
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
/* pseudo code by the compiler */
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];
}
/* pseudo code by the compiler */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);
Reference Count
uintptr_t _objc_rootRetainCount(id obj):don't return reliable value all the time
struct SideTable {
// 保证原子操作的自旋锁
spinlock_t slock;
// 引用计数的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
};
SideTable 结构体重定了几个非常重要的变量。
// The order of these bits is important.
#define SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0)
#define SIDE_TABLE_DEALLOCATING (1UL<<1) // MSB-ward of weak bit
#define SIDE_TABLE_RC_ONE (1UL<<2) // MSB-ward of deallocating bit
#define SIDE_TABLE_RC_PINNED (1UL<<(WORD_BITS-1))//最高位字节为0
#define SIDE_TABLE_RC_SHIFT 2
#define SIDE_TABLE_FLAG_MASK (SIDE_TABLE_RC_ONE-1)
3.retainCount
- (NSUInteger)retainCount {
return ((id)self)->rootRetainCount();
}
inline uintptr_t
objc_object::rootRetainCount()
{
if (isTaggedPointer()) return (uintptr_t)this;
return sidetable_retainCount();
}
uintptr_t
objc_object::sidetable_retainCount()
{
SideTable& table = SideTables()[this];
size_t refcnt_result = 1;
table.lock();
RefcountMap::iterator it = table.refcnts.find(this);
if (it != table.refcnts.end()) {
// this is valid for SIDE_TABLE_RC_PINNED too
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;//右移两位
}
table.unlock();
return refcnt_result;
}
4.retain
- (id)retain {
return ((id)self)->rootRetain();
}
// Base retain implementation, ignoring overrides.
// This does not check isa.fast_rr; if there is an RR override then
// it was already called and it chose to call [super retain].
inline id
objc_object::rootRetain()
{
if (isTaggedPointer()) return (id)this;
return sidetable_retain();
}
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];
table.lock();
size_t& refcntStorage = table.refcnts[this];
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
//相当于+(1 << 2)
refcntStorage += SIDE_TABLE_RC_ONE;
}
table.unlock();
return (id)this;
}
5.release
- (oneway void)release {
((id)self)->rootRelease();
}
inline bool
objc_object::rootRelease()
{
if (isTaggedPointer()) return false;
return sidetable_release(true);
}
// rdar://20206767
// return uintptr_t instead of bool so that the various raw-isa
// -release paths all return zero in eax
uintptr_t
objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];
bool do_dealloc = false;
table.lock();
RefcountMap::iterator it = table.refcnts.find(this);
if (it == table.refcnts.end()) {
do_dealloc = true;
table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
} else if (it->second < SIDE_TABLE_DEALLOCATING) {
// 判断引用计数是否为0,如果小于SIDE_TABLE_DEALLOCATING,只有00000001或者00000000,两种情况下,引用计数都为0,所以需要将do_dealloc置为0
// SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
} else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
// 如果符合这个条件,即:引用计数没有溢出(最高位为0),do_dealloc为0,weak_reference为0)
it->second -= SIDE_TABLE_RC_ONE;
}
table.unlock();
if (do_dealloc && performDealloc) {
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
}
return do_dealloc;
}
Table of Contents generated with DocToc
Chapter1 Life Before Automatic Reference Counting
Reference Counted Memory Management Overview
Exploring Memory Management Further
You Have Ownership of Any Objects You Create
You Can Take Ownership of an Object Using retain
Sometimes methods that are not in the alloc/new/copy/mutableCopy method group return an object : you haven't create it, so you don't have ownership of it.
When No Longer Needed, You Must Relinquish Ownership of an Object You Own
how a method return a created object?
You Must Not Relinquish Ownership of an Object You Don’t Own
Implementing alloc, retain, release, and dealloc
Although opensourced, I think this
guess
procedure still worth of being read so HERE WE GO.But still, without having the implementation of NSObject itself, it is hard to see the whole picture: NSObject has been opensourceGNUStep implementation
1.The alloc Method
2.The retain Method
3.The release Method
4.The dealloc Method
Apple’s Implementation of alloc, retain, release, and dealloc
1.The alloc method
2.retainCount, retain, and release
3.Apple implementation vs GNUStep implementation
Benefits:
GNUStep implementation:
Apple implementation:
Autorelease
1.Automatic Variables in C language:when left the variable scope,auto variable 'int a' is disposed of and can't be accessed anymore.
2.autoRelease:when execution leaves a code block, the “release” method is called on the object automatically
3.Caution:
(1)临时处理多个对象的释放
(2)类方法返回来一个没有ownership的对象
(3)不要对NSAutoReleasePool发送autoRelease方法,因为它已经被override抛出exception
No need to explicitly use the NSAutoreleasePool object in
the main Runloop
Implementing autorelease
Chapter2 ARC Rules
ARC related:
Chapter2组织方式:
Ownership qualifiers
1.__strong ownership qualifier
__strong 代表了对象的ownership (MRC下对象需要通过alloc/new/copy/muteableCopy或者retain来获得ownership)
__strong离开了{ }之后就会消失,即是说作用域在{ }之间
一个对象没有ownership将会被disposed
2.__weak ownership qualifier
3.__unsafe_unretained ownership qualifier
4.__autoreleasing ownership qualifier
①When an object is returned from a method, the compiler checks if the method begins with alloc/new/copy/mutableCopy, and if not, the returned object is automatically registered to the autorelease pool
②Exceptionally, any method whose name begins with init, doesn’t register the return value to autoreleasepool
③
the weak ownership qualifier is used to avoid cyclic reference. When a variable with a weak qualifier is used, the object is always registered in autoreleasepool.Why does the object need to be registered in autoreleasepool in order to use the object via the weak qualified variable? Because a variable, which is qualified with weak, does not have a strong reference, the object might be disposed of at any point. If the object is registered in autoreleasepool, until @autoreleasepool block is left, the object must exist. So, to use the objects via __weak variable safely, the object is registered in autoreleasepool automatically.(to be proved)④ Any pointers to ‘id’ or object types are qualified with __autoreleasing as default.
5.Returning a Result as the Argument
Rules
8.‘id’ and ‘void’ have to be cast explicitly.
With ARC,To cast between ‘id’ or object types and 'void',you can use __bridge
__bridge_retained
和__bridge_transfer
都是用来解决void *
的ownership的Core Foundation
OBJECTIVE-C OBJECT AND CORE FOUNDATION OBJECT
1.Core Foundation,mainly written in C;has reference counting
2.Toll-Free Bridged Types:There are a number of data types in the Core Foundation framework and the Foundation framework that can be used interchangeably. Data types that can be used interchangeably are also referred to as toll-free bridged data types
CFBridgingRetain function
Property
Chapter 3 ARC implementation
__strong
an object is not obtained by the alloc/new/copy/mutableCopy
objc_retainAutoreleasedReturnValue:
objc_retainAutoreleasedReturnValue
function is for performance optimization. It is inserted because the NSMutableArray class method array is not in the alloc/new/copy/mutableCopy method group.The compiler
inserts this function every time just after the invocation of a method if the method is not in the group. As the name suggests, itretains
an object returned from a method or function afterthe object is added in autorelease pool
.objc_retainAutoreleasedReturnValue
function expects that anobjc_autoreleaseReturnValue
function has been called inside the method. Any methods, that are not in the alloc/new/copy/mutableCopy group, have to callobjc_autoreleaseReturnValue
objc_autoreleaseReturnValue
objc_autoreleaseReturnValue
adds an object to autorelease pool and returns itobjc_autoreleaseReturnValue
checksthe caller’s executable code
and if the code callsobjc_retainAutoreleasedReturnValue
just after calling this method: it just returns the object to the caller,So, performance will be improved.__weak
When an object is accessed through a __weak qualified variable, the object is added to the autorelease pool:wrong guideobjc_storeWeak
:When an Object Is Discarded
key
from thereference table
.Assigning a Newly Created Object
Adding to autorelease pool Automatically验证汇编代码: Xcode → Debug → Debug workflow → Always show Disassembly. 输入下面的例子,会看到编译器插入的是release不是autorelease
In conclusion, this design of weak ensure that during the usage of weak pointer, its state is consistent. The
new
implmenetation of weak ofApple LLVM version 8.0.0 (clang-800.0.42.1)
do not postpond the release to autoreleasepool, but useobjc_release
directly.苹果list
参考资料1
参考资料2
__autoreleasing
Reference Count
uintptr_t _objc_rootRetainCount(id obj)
:don't return reliable value all the timeNSObject开源release,retain,dealloc内存管理的实现
引用计数的储存
有些对象如果支持使用
TaggedPointer
,苹果会直接将其指针值作为引用计数返回;否则 Runtime 会使用一张散列表
来管理引用计数。一些概念
1.TaggedPointer
判断当前对象是否在使用 TaggedPointer 是看标志位是否为 1;id的isTaggedPointer()方法经常会在操作引用计数时用到,因为这决定了存储引用计数的策略。
2.散列表
3.retainCount
4.retain
5.release
6. alloc
7.dealloc
key
from thereference table
8.autorelease
参考资料:
黑幕背后的Autorelease
参考资料:
1.Objective-C 引用计数原理,部分地方最新的obj4版本已经改了
2.iOS进阶——iOS(Objective-C)内存管理·二