A look inside blocks: Episode 1

原文地址:http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/

一篇不错的文章地址:http://blog.csdn.net/wildfireli/article/details/22063001

Today I have been taking a look at the internals of how blocks work from a compiler perspective. By blocks, I mean the closure that Apple added to the C language and is now well and truly established as part of the language from a clang/LLVM perspective. I had been wondering just what a “block” was and how it magically seems to appear as an Objective-C object (you can copyretainrelease them for instance). This blog post delves into blocks a little.

今天我从编译器的角度看看block的内部是如何工作的,

我是好奇一个block 是什么,并且it是怎么魔法般的作为一个oc对象出现(例如你能copy,retain,释放他们),这篇博客深入研究了block一点点。

The basics

This is a block:

1
2
3

2
3
void(^block)(void) = ^{
    NSLog(@"I'm a block!");
};

This creates a variable called block which has a simple block assigned to it. That’s easy. Done right? No. I wanted to understand what exactly the compiler does with that bit of code.

这里创建了一个叫block的变量,这个变量有一个简单的代码块(block)赋给它,那是简单的,确实嘛?不是,我想要确切的理解编译器是怎么处理那些代码的。

Further more, you can pass variables to block:

进一步,你能传递一个变量给block.

1
2
3

2
3
void(^block)(int a) = ^{
    NSLog(@"I'm a block! a = %i", a);
};

Or even return values from them:

或者甚至从代码块中返回值

1
2
3
4

2
3
4
int(^block)(void) = ^{
    NSLog(@"I'm a block!");
    return 1;
};

And being a closure, they wrap up the context they are in:

作为一个闭包,他们总结了他们所在的上下文

1
2
3
4

2
3
4
int a = 1;
void(^block)(void) = ^{
    NSLog(@"I'm a block! a = %i", a);
};

So just how does the compiler sort all of these bits out then? That is what I was interested in.

所以编译器是怎么解决这些代码的呢,这正是我感兴趣的地方

Diving into a simple example

My first idea was to look at how the compiler compiles a very simple block. Consider the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <dispatch/dispatch.h>

typedef void(^BlockA)(void);

__attribute__((noinline))
void runBlockA(BlockA block) {
    block();
}

void doBlockA() {
    BlockA block = ^{
        // Empty block
    };
    runBlockA(block);
}

The reason for the two functions is that I wanted to see both how a block is “called” and how a block is set up. If both of these were in one function then the optimiser might be too clever and we wouldn’t see anything interesting. I had to make the runBlockA function noinline so that the optimiser didn’t just inline that function in doBlockA reducing it to the same problem.

选这两个函数的原因是我想要看看一个block是怎么被呼唤的,同时想看看一个block 是怎么设置的。如果这两个函数都是在一个函数中,然后优化器也许太聪明,导致我们不能看到任何有趣的事情,我不得不使函数runBlockA 非内联的,以致优化器没有内联那个函数进doBlockA

The relevant bits of that code compiles down to this (armv7, O3):

1
2
3
4
5
6
7
8

2
3
4
5
6
7
8
    .globl  _runBlockA
    .align  2
    .code   16                      @ @runBlockA
    .thumb_func     _runBlockA
_runBlockA:
@ BB#0:
    ldr     r1, [r0, #12]
    bx      r1

This is the runBlockA function. So, that’s fairly simple then. Taking a look back up to the source for this, the function is just calling the block. r0 (register 0) is set to the first argument of the function in the ARM EABI.(ARM:Advanced RISC Machines,EABI:Embedded application binary interface 应用二进制接口) The first instruction therefore means that r1 is loaded from the value held in the adress stored in r0 + 12. Think of this as a dereference of a pointer, reading 12 bytes into it. Then we branch to that address. Notice that r1 is used, which means that r0 is still the block itself. So it’s likely that the function this is calling takes the block as its first parameter.

这是一个runBlockA函数,那是相当的简单的,让我们来看一下这个函数的源头,

 

From this I can ascertain that the block is likely some sort of structure where the function the block should execute is stored 12 bytes into said structure. And when a block is passed around, a pointer to one of these structures is passed.

Now onto the doBlockA method:

1
2
3
4
5
6
7
8
9
10

2
3
4
5
6
7
8
9
10
    .globl  _doBlockA
    .align  2
    .code   16                      @ @doBlockA
    .thumb_func     _doBlockA
_doBlockA:
    movw    r0, :lower16:(___block_literal_global-(LPC1_0+4))
    movt    r0, :upper16:(___block_literal_global-(LPC1_0+4))
LPC1_0:
    add     r0, pc
    b.w     _runBlockA

Well, that’s pretty simple also. This is a program counter relative load. You can just think of this as loading the address of the variable called ___block_literal_global into r0. Then the runBlockA function is called. So given we know that the block object is being passed to runBlockA, this ___block_literal_global must be that block object.

Now we’re getting somewhere! But what exactly is ___block_literal_global? Well, looking through the assembly we find this:

1
2
3
4
5
6
7

2
3
4
5
6
7
    .align  2                       @ @__block_literal_global
___block_literal_global:
    .long   __NSConcreteGlobalBlock
    .long   1342177280              @ 0x50000000
    .long   0                       @ 0x0
    .long   ___doBlockA_block_invoke_0
    .long   ___block_descriptor_tmp

Ah ha! That looks very much like a struct to me. There’s 5 values in the struct, each of which are 4-bytes (long). This must be the block object that runBlockA was acting upon. And look, 12 bytes into the struct is what looks suspiciously like a function pointer as it’s called ___doBlockA_block_invoke_0. Remember that was what the runBlockAfunction was jumping to.

But what is __NSConcreteGlobalBlock? Well, we’ll come back to that. It’s ___doBlockA_block_invoke_0 and ___block_descriptor_tmp that are of interest since these also appear in the assembly:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    .align  2
    .code   16                      @ @__doBlockA_block_invoke_0
    .thumb_func     ___doBlockA_block_invoke_0
___doBlockA_block_invoke_0:
    bx      lr

    .section        __DATA,__const
    .align  2                       @ @__block_descriptor_tmp
___block_descriptor_tmp:
    .long   0                       @ 0x0
    .long   20                      @ 0x14
    .long   L_.str
    .long   L_OBJC_CLASS_NAME_

    .section        __TEXT,__cstring,cstring_literals
L_.str:                                 @ @.str
    .asciz   "v4@?0"

    .section        __TEXT,__objc_classname,cstring_literals
L_OBJC_CLASS_NAME_:                     @ @"\01L_OBJC_CLASS_NAME_"
    .asciz   "\001"

That ___doBlockA_block_invoke_0 looks suspiciously like the actual block implementation itself, since the block we used was an empty block. This function just returns straight away, exactly how we’d expect an empty function to be compiled.

Then comes ___block_descriptor_tmp. This appears to be another struct, this time with 4 values in it. The second one is 20 which is how big the ___block_literal_global is. Maybe that is a size value then? There’s also a C-string called .str which has a value v4@?0. This looks like some form of encoding of a type. That might be an encoding of the block type (i.e. it returns void and takes no parameters). The other values I have no idea about.

But the source is out there, isn’t it?

Yes, the source is out there! It’s part of the compiler-rt project within LLVM. Trawling through the code I found the following definitions withinBlock_private.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

struct Block_layout {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

Those look awfully familiar! The Block_layout struct is what our ___block_literal_global is and the Block_descriptor struct is what our___block_descriptor_tmp is. And look, I was right about the size being the 2nd value of the descriptor. The bit that’s slightly strange is the 3rd and 4th values of the Block_descriptor. These look like they should be function pointers but in our compiled case they seemed to be 2 strings. I’ll ignore that little point for now.

The isa of Block_layout is interesting as that must be what _NSConcreteGlobalBlock is and also must be how a block can emulate being an Objective-C object. If _NSConcreteGlobalBlock is a Class then the Objective-C message dispatch system will happily treat a block object as a normal object. This is similar to how toll-free bridging works. For more information on that side of things, have a read of Mike Ash’s excellent blog post about it.

Having pieced all that together, the compiler looks like it’s treating the code as something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import <dispatch/dispatch.h>

__attribute__((noinline))
void runBlockA(struct Block_layout *block) {
    block->invoke();
}

void block_invoke(struct Block_layout *block) {
    // Empty block function
}

void doBlockA() {
    struct Block_descriptor descriptor;
    descriptor->reserved = 0;
    descriptor->size = 20;
    descriptor->copy = NULL;
    descriptor->dispose = NULL;

    struct Block_layout block;
    block->isa = _NSConcreteGlobalBlock;
    block->flags = 1342177280;
    block->reserved = 0;
    block->invoke = block_invoke;
    block->descriptor = descriptor;

    runBlockA(&block);
}

That’s good to know. It makes a lot more sense now what’s going on under the hood of blocks.

What’s next?

Next up I will take a look at a block that takes a parameter and a block that captures variables from the enclosing scope. These will surely make things a bit different! So, watch this space for more.

 

第二次学习:

id __attribute__((objc_ownership(strong))) obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));

 

 

id obj = objc_msgSend(NSObject, @selector(alloc));

objc_msgSend(obj,selector(init));

objc_release(obj);

https://www.jianshu.com/p/701da54bd78c

 

 

https://segmentfault.com/q/1010000005034363

 

 

block是对对象,是继承NSObject的

 

Block内存管理的规则:

1,Block指针会在方法或函数结束后release掉,此时内存是储存在Stack里。

2,如果要在保存Block指针,需要用到copy方法(类似于NSObject),此时内存储存在Heap里。

3,Block函数体里的变量会被自动Retain,等Block结束掉后会Release。

4,__block 前缀标明的变量,不会自动Reatin。

Block Copy时的注意事项:

1,在block里如果直接操作self,则self会自动retain。

2,在block里如果操作类变量,则变量所属的类会自动retain

3、一般如果我们不写,默认的修饰符是————strong

 

 

http://clang.llvm.org/docs/AutomaticReferenceCounting.html翻译

1、Blocks are a C language extension for creating anonymous functions. block是创建匿名函数的c的延展。

2、Rationale基本原理   Spelling拼写

3、Evolution 演变,进化

4semantics语法定义

5、Ownership qualification资格

1、Background

This document assumes a basic familiarity with C.

Blocks are a C language extension for creating anonymous(匿名的) functions. Users interact with and transfer block objects using block pointers, which are represented like a normal pointer. A block may capture values from local variables; when this occurs, memory must be dynamically allocated. The initial allocation is done on the stack(栈), but the runtime provides a Block_copy function which, given a block pointer, either copies the underlying block object to the heap(堆)(最开始分配是在栈,然后 通过copu方法拷贝到堆), setting its reference count to 1 and returning the new block pointer, or (if the block object is already on the heap) increases its reference count by 1. The paired function(配对函数) isBlock_release, which decreases the reference count by 1 and destroys the object if the count reaches zero and is on the heap.

Objective-C is a set of language extensions(语言延展的集合), significant enough to be considered a different language. It is a strict superset of C(C语言严格的超集). The extensions can also be imposed on C++(对C++的延展产生C++语言), producing a language called Objective-C++. The primary feature is a single-inheritance(单继承) object system; we briefly describe the modern dialect(方言,土话;同源语;行话;个人用语特征).

Objective-C defines a new type kind, collectively(全体地) called the object pointer types. This kind has two notable(显著的) builtin(固定的) members, id and Class; id is the final supertype of all object pointers. The validity(有效性) of conversions(转化) between object pointer types is not checked at runtime. Users may define classes; each class is a type, and the pointer to that type is an object pointer type. A class may have a superclass; its pointer type is a subtype of its superclass’s pointer type. A class has a set of ivars, fields which appear on all instances of that class. For every class T there’s an associated metaclass(元类); it has no fields(没有字段), its superclass is the metaclass of T’s superclass, and its metaclass is a global class. Every class has a global object whose class is the class’s metaclass; metaclasses have no associated type, so pointers to this object have type Class.

A class declaration (@interface) declares a set of methods. A method has a return type, a list of argument types, and a selector: a name like foo:bar:baz:, where the number of colons corresponds to the number of formal arguments. A method may be an instance method, in which case it can be invoked on objects of the class, or a class method, in which case it can be invoked on objects of the metaclass. A method may be invoked by providing an object (called the receiver) and a list of formal arguments interspersed with the selector, like so:

[receiver foo: fooArg bar: barArg baz: bazArg]

This looks in the dynamic class of the receiver for a method with this name, then in that class’s superclass, etc., until it finds something it can execute. The receiver “expression” may also be the name of a class, in which case the actual receiver is the class object for that class, or (within method definitions) it may be super, in which case the lookup algorithm starts with the static superclass instead of the dynamic class. The actual methods dynamically found in a class are not those declared in the @interface, but those defined in a separate @implementation declaration; however, when compiling a call, typechecking is done based on the methods declared in the @interface.

Method declarations may also be grouped into protocols, which are not inherently associated with any class, but which classes may claim to follow. Object pointer types may be qualified with additional protocols that the object is known to support.

Class extensions are collections of ivars and methods, designed to allow a class’s @interface to be split across(被跨越) multiple files; however, there is still a primary implementation file which must see the @interfaces of all class extensions. Categories allow methods (but not ivars) to be declared post hoc on an arbitrary class; the methods in the category’s @implementation will be dynamically added to that class’s method tables which the category is loaded at runtime, replacing those methods in case of a collision(万一发生碰撞).

In the standard environment, objects are allocated on the heap(标准的环境里面,对象被分配在堆), and their lifetime is manually managed using a reference count. This is done using two instance methods which all classes are expected to implement: retain increases the object’s reference count by 1, whereas release decreases it by 1 and calls the instance method dealloc if the count reaches 0. To simplify certain operations, there is also an autorelease pool, a thread-local list of objects to call release on later; an object can be added to this pool by calling autorelease on it.

Block pointers may be converted to type id; block objects are laid out in(被放置在) a way that makes them compatible with Objective-C objects. There is a builtin(内装式) class that all block objects are considered to be objects of; this class implements retain by adjusting the reference count, not by calling Block_copy. 

2、Evolution (进化)

ARC is under continual(持续地) evolution, and this document must be updated as the language progresses.

If a change increases the expressiveness(表达能力) of the language, for example by lifting a restriction(解除限制) or by adding new syntax, the change will be annotated(待注释的) with a revision marker(版本的标志), like so:

ARC applies to Objective-C pointer types, block pointer types, and [beginning Apple 8.0, LLVM 3.8] BPTRs declared within extern "BCPL" blocks.

 

For now, it is sensible(明智的) to version this document by the releases of its sole implementation (and its host project), clang. “LLVM X.Y” refers to an open-source release of clang from the LLVM project. “Apple X.Y” refers to an Apple-provided release of the Apple LLVM Compiler. Other organizations that prepare their own, separately-versioned clang releases and wish to maintain similar information in this document should send requests to cfe-dev.

If a change decreases the expressiveness of the language, for example by imposing a new restriction(实行新的限制), this should be taken as an oversight(监督监管) in the original specification(规格) and something to be avoided in all versions. Such changes are generally to be avoided.

3、General

Automatic Reference Counting implements automatic memory management for Objective-C objects and blocks, freeing the programmer from the need to explicitly insert retains and releases. It does not provide a cycle collector(没有提供一个循环colletor); users must explicitly(明确的) manage the lifetime of their objects, breaking cycles manually or with weak or unsafe references.

ARC may be explicitly enabled with the compiler flag -fobjc-arc. It may also be explicitly disabled with the compiler flag -fno-objc-arc. The last of these two flags appearing on the compile line “wins”.If ARC is enabled, __has_feature(objc_arc) will expand to 1 in the preprocessor. For more information about __has_feature, see the language extensions document.

4、Retainable object pointers(可持有的对象指针)

This section describes retainable object pointers, their basic operations, and the restrictions imposed on their use under ARC. Note in particular that it covers the rules for pointer values (patterns of bits indicating the location of a pointed-to object), not pointer objects (locations in memory which store pointer values). The rules for objects are covered in the next section.

retainable object pointer (or “retainable pointer”) is a value of a retainable object pointer type (“retainable type”). There are three kinds of retainable object pointer types:

  • block pointers (formed by applying the caret (^) declarator sigil to a function type)
  • Objective-C object pointers (id, Class, NSFoo*, etc.)
  • typedefs marked with __attribute__((NSObject))

Other pointer types, such as int* and CFStringRef, are not subject to ARC’s semantics and restrictions.

Rationale

We are not at liberty to require all code to be recompiled with ARC; therefore, ARC must interoperate with Objective-C code which manages retains and releases manually. In general, there are three requirements in order for a compiler-supported reference-count system to provide reliable interoperation:

  • The type system must reliably identify which objects are to be managed. An int* might be a pointer to a malloc’ed array, or it might be an interior pointer to such an array, or it might point to some field or local variable. In contrast, values of the retainable object pointer types are never interior.
  • The type system must reliably indicate how to manage objects of a type. This usually means that the type must imply a procedure for incrementing and decrementing retain counts. Supporting single-ownership objects requires a lot more explicit mediation in the language.
  • There must be reliable conventions for whether and when “ownership” is passed between caller and callee, for both arguments and return values. Objective-C methods follow such a convention very reliably, at least for system libraries on Mac OS X, and functions always pass objects at +0. The C-based APIs for Core Foundation objects, on the other hand, have much more varied transfer semantics.

The use of __attribute__((NSObject)) typedefs is not recommended. If it’s absolutely necessary to use this attribute, be very explicit about using the typedef, and do not assume that it will be preserved by language features like __typeof and C++ template argument substitution.

Rationale

Any compiler operation which incidentally(顺便) strips type “sugar” from a type will yield a type without the attribute, which may result in unexpected behavior.

 

5、Rstrictions

5.1Weak-unavailable types(weak 不可行的类型)

It is explicitly permitted for Objective-C classes to not support __weak references. It is undefined behavior to perform an operation with weak assignment semantics with a pointer to an Objective-C object whose class does not support __weak references.

Rationale

Historically(历史上的), it has been possible for a class to provide its own reference-count implementation by overriding retain, release, etc. However, weak references to an object require coordination(协调) with its class’s reference-count implementation because, among other things, weak loads and stores must be atomic with respect to the final release. Therefore, existing custom reference-count implementations will generally not support weak references without additional effort. This is unavoidable without breaking binary compatibility(兼容性).

A class may indicate that it does not support weak references by providing the objc_arc_weak_reference_unavailable attribute on the class’s interface declaration(objc_arc_weak_reference_unavailable 提供这个标识符,可以让这个类不支持weak属性). A retainable object pointer type is weak-unavailable if is a pointer to an (optionally protocol-qualified) Objective-C class T where T or one of its superclasses has the objc_arc_weak_reference_unavailable attribute(如果父类有这个标识符,那么下面的类如果用到weak,那是不可行的). A program is ill-formed(不合语法的) if it applies the __weak ownership qualifier to a weak-unavailable type or if the value operand(操作数) of a weak assignment operation has a weak-unavailable type.

5.2 Storage duration of __autoreleaseing objects

A program is ill-formed(合格的) if it declares an __autoreleasing object of non-automatic storage duration. A program is ill-formed if it captures an __autoreleasing object in a block or, unless by reference, in a C++11 lambda(匿名函数).

Rationale

Autorelease pools are tied to the current thread and scope(范围) by their nature. While it is possible to have temporary objects whose instance variables are filled with autoreleased objects, there is no way that ARC can provide any sort of safety guarantee there.

It is undefined behavior if a non-null pointer is assigned to an __autoreleasing object while an autorelease pool is in scope and then that object is read after the autorelease pool’s scope is left.

5.3 conversion of pointers to ownership-qualified types

A program is ill-formed if an expression of type T* is converted, explicitly or implicitly, to the type U*, where T and U have different ownership qualification, unless:

  • T is qualified with __strong, __autoreleasing, or __unsafe_unretained, and U is qualified with both const and __unsafe_unretained; or
  • either T or U is cv void, where cv is an optional sequence of non-ownership qualifiers; or
  • the conversion is requested with a reinterpret_cast in Objective-C++; or
  • the conversion is a well-formed pass-by-writeback .
  • The analogous(类似的) rule applies to T& and U& in Objective-C++.

Rationale

These rules provide a reasonable level of type-safety for indirect pointers, as long as the underlying memory is not deallocated. The conversion to const__unsafe_unretained is permitted because the semantics of reads are equivalent across all these ownership semantics, and that’s a very useful and common pattern. The interconversion with void* is useful for allocating memory or otherwise escaping the type system, but use it carefully. reinterpret_cast is considered to be an obvious enough sign of taking responsibility for any problems.

It is undefined behavior to access an ownership-qualified object through an lvalue of a differently-qualified type, except that any non-__weak object may be read through an __unsafe_unretained lvalue.

It is undefined behavior if a managed operation is performed on a __strong or __weak object without a guarantee that it contains a primitive(原始的,简单的) zero bit-pattern, or if the storage for such an object is freed or reused without the object being first assigned a null pointer.

Rationale

ARC cannot differentiate(区分) between an assignment operator which is intended to “initialize” dynamic memory and one which is intended to potentially(可能的) replace a value. Therefore the object’s pointer must be valid before letting ARC at it. Similarly, C and Objective-C do not provide any language hooks for destroying objects held in dynamic memory, so it is the programmer’s responsibility to avoid leaks (__strong objects) and consistency(一致性) errors (__weak objects).

These requirements are followed automatically in Objective-C++ when creating objects of retainable object owner type with new or new[] and destroying them with delete, delete[], or a pseudo-destructor expression. Note that arrays of nontrivially-ownership-qualified type are not ABI compatible with non-ARC code because the element type is non-POD: such arrays that are new[]’d in ARC translation units cannot be delete[]’d in non-ARC translation units and vice-versa.

5.4 passing to an out parameter by writeback

If the argument passed to a parameter of type T __autoreleasing * has type U oq *, where oq is an ownership qualifier, then the argument is a candidate for pass-by-writeback` if:

  • oq is __strong or __weak, and
  • it would be legal to initialize a T __strong * with a U __strong *.

For purposes of overload(超载) resolution, an implicit(含蓄的) conversion sequence requiring a pass-by-writeback is always worse than an implicit conversion sequence not requiring a pass-by-writeback.

The pass-by-writeback is ill-formed if the argument expression does not have a legal form:

  • &var, where var is a scalar variable of automatic storage duration with retainable object pointer type
  • a conditional expression where the second and third operands are both legal forms
  • a cast whose operand is a legal form
  • a null pointer constant

Rationale

The restriction in the form of the argument serves two purposes. First, it makes it impossible to pass the address of an array to the argument, which serves to protect against an otherwise serious risk of mis-inferring an “array” argument as an out-parameter. Second, it makes it much less likely that the user will see confusing aliasing problems due to the implementation, below, where their store to the writeback temporary is not immediately seen in the original argument variable.

A pass-by-writeback is evaluated as follows:

  1. The argument is evaluated to yield(屈服) a pointer p of type U oq *.
  2. If p is a null pointer, then a null pointer is passed as the argument, and no further work is required for the pass-by-writeback.
  3. Otherwise, a temporary of type T __autoreleasing is created and initialized to a null pointer.
  4. If the parameter is not an Objective-C method parameter marked out, then *p is read, and the result is written into the temporary with primitive semantics.
  5. The address of the temporary is passed as the argument to the actual call.
  6. After the call completes, the temporary is loaded with primitive semantics, and that value is assigned into *p.

Rationale

This is all admittedly(公认的) convoluted(复杂的). In an ideal world, we would see that a local variable is being passed to an out-parameter and retroactively(追溯的,反动的) modify its type to be __autoreleasing rather than __strong. This would be remarkably(显著的) difficult and not always well-founded(有根据的) under the C type system. However, it was judged unacceptably invasive(侵略性的,攻击性的) to require programmers to write __autoreleasing on all the variables they intend to use for out-parameters. This was the least bad solution.(那是最坏的解决方案)

5.5ownership-qualified fields of structs and unions

A program is ill-formed if it declares a member of a C struct or union to have a nontrivially(非平凡地) ownership-qualified type.

Rationale

The resulting type would be non-POD in the C++ sense, but C does not give us very good language tools for managing the lifetime of aggregates(总量), so it is more convenient to simply forbid(禁止) them. It is still possible to manage this with a void* or an __unsafe_unretained object.

This restriction does not apply in Objective-C++. However, nontrivally(非平凡的) ownership-qualified types are considered non-POD: in C++11 terms, they are not trivially (平凡的)default constructible(可构成的), copy constructible(可构成的), move constructible, copy assignable, move assignable, or destructible(可破坏的). It is a violation of C++’s One Definition Rule to use a class outside of ARC that, under ARC, would have a nontrivially(非平凡的) ownership-qualified member.

Rationale

Unlike in C, we can express all the necessary ARC semantics for ownership-qualified subobjects as suboperations(运作) of the (default) special member functions for the class. These functions then become non-trivial(非凡的,面积较大的). This has the non-obvious result that the class will have a non-trivial copy constructor(构造函数) and non-trivial destructor(破坏者); if this would not normally be true outside of ARC, objects of the type will be passed and returned in an ABI-incompatible manner.

6、Method families

An Objective-C method may fall into a method family, which is a conventional(传统的) set of behaviors ascribed(归因于) to it by the Cocoa conventions(惯例).

A method is in a certain method family if:

  • it has a objc_method_family attribute placing it in that family; or if not that,
  • it does not have an objc_method_family attribute placing it in a different or no family, and
  • its selector falls into the corresponding selector family, and
  • its signature obeys(服从) the added restrictions(限制) of the method family.

A selector is in a certain selector family if, ignoring any leading underscores, the first component of the selector either consists entirely of the name of the method family or it begins with that name followed by a character other than a lowercase letter. For example, _perform:with: and performWith: would fall into the performfamily (if we recognized one), but performing:with would not.

The families and their added restrictions are:

  • alloc methods must return a retainable object pointer type.
  • copy methods must return a retainable object pointer type.
  • mutableCopy methods must return a retainable object pointer type.
  • new methods must return a retainable object pointer type.
  • init methods must be instance methods and must return an Objective-C pointer type. Additionally, a program is ill-formed if it declares or contains a call to an init method whose return type is neither id nor a pointer to a super-class or sub-class of the declaring class (if the method was declared on a class) or the static receiver type of the call (if it was declared on a protocol).
    Rationale
    There are a fair number of existing methods with init-like selectors which nonetheless don’t follow the init conventions. Typically these are either accidental naming collisions or helper methods called during initialization. Because of the peculiar retain/release behavior of init methods, it’s very important not to treat these methods as init methods if they aren’t meant to be. It was felt that implicitly defining these methods out of the family based on the exact relationship between the return type and the declaring class would be much too subtle and fragile. Therefore we identify a small number of legitimate-seeming return types and call everything else an error. This serves the secondary purpose of encouraging programmers not to accidentally give methods names in the init family.
    Note that a method with an init-family selector which returns a non-Objective-C type (e.g. void) is perfectly well-formed; it simply isn’t in the init family.

A program is ill-formed if a method’s declarations, implementations, and overrides do not all have the same method family.

6.1 Explicit method family control

A method may be annotated with the objc_method_family attribute to precisely(精确的) control which method family it belongs to. If a method in an @implementation does not have this attribute, but there is a method declared in the corresponding @interface that does, then the attribute is copied to the declaration in the @implementation. The attribute is available outside of ARC, and may be tested for with the preprocessor query __has_attribute(objc_method_family).

The attribute is spelled __attribute__((objc_method_family( family ))). If family is none, the method has no family, even if it would otherwise be considered to have one based on its selector and type. Otherwise, family must be one of alloc, copy, init, mutableCopy, or new, in which case the method is considered to belong to the corresponding family regardless of its selector. It is an error if a method that is explicitly added to a family in this way does not meet the requirements of the family other than the selector naming convention.

Rationale

The rules codified(编撰的) in this document describe the standard conventions of Objective-C. However, as these conventions have not heretofore been enforced by an unforgiving mechanical system, they are only imperfectly kept, especially as they haven’t always even been precisely defined. While it is possible to define low-level ownership semantics with attributes like ns_returns_retained, this attribute allows the user to communicate semantic intent, which is of use both to ARC (which, e.g., treats calls to init specially) and the static analyzer.

6.2 Semantics of method families

 

A method’s membership in a method family may imply(意味着) non-standard semantics for its parameters and return type.

Methods in the alloc, copy, mutableCopy, and new families — that is, methods in all the currently-defined families except init — implicitly return a retained object as if they were annotated with the ns_returns_retained attribute. This can be overridden by annotating the method with either of the ns_returns_autoreleased or ns_returns_not_retained attributes.

Properties also follow same naming rules as methods. This means that those in the alloc, copy, mutableCopy, and new families provide access to retained objects . This can be overridden by annotating the property with ns_returns_not_retained attribute.

6.3 

Semantics of init

Methods in the init family implicitly(含蓄地) consume  their self parameter and return a retained object . Neither of these properties can be altered through attributes.

A call to an init method with a receiver that is either self (possibly parenthesized or casted) or super is called a delegate init call. It is an error for a delegate init call to be made except from an init method, and excluding blocks within such methods.

As an exception to the usual rule , the variable self is mutable in an init method and has the usual semantics for a __strong variable. However, it is undefined behavior and the program is ill-formed, no diagnostic required, if an init method attempts to use the previous value of self after the completion of a delegate init call. It is conventional, but not required, for an init method to return self.

It is undefined behavior for a program to cause two or more calls to init methods on the same object, except that each init method invocation may perform at most one delegate init call.

6.4 related result types

Certain methods are candidates to have related result types:

  • class methods in the alloc and new method families
  • instance methods in the init family
  • the instance method self
  • outside of ARC, the instance methods retain and autorelease

If the formal result type of such a method is id or protocol-qualified id, or a type equal to the declaring class or a superclass, then it is said to have a related result type. In this case, when invoked in an explicit message send, it is assumed to return a type related to the type of the receiver:

  • if it is a class method, and the receiver is a class name T, the message send expression has type T*; otherwise
  • if it is an instance method, and the receiver has type T, the message send expression has type T; otherwise
  • the message send expression has the normal result type of the method.

This is a new rule of the Objective-C language and applies outside of ARC.

Rationale

ARC’s automatic code emission(发射,散发) is more prone(易于的,倾向的) than most code to signature errors, i.e. errors where a call was emitted against one method signature, but the implementing method has an incompatible(不相容的,矛盾的) signature. Having more precise type information helps drastically(彻底的) lower this risk, as well as catching a number of latent(潜在的) bugs.

7、Optimization

Within this section, the word function will be used to refer to any structured unit of code, be it a C function, an Objective-C method, or a block.(function 被用来指向任何代码的结构单元,不论是c函数,还是oc方法,或者block)

This specification(规格) describes ARC as performing specific retain and release operations on retainable object pointers at specific points during the execution of a program. These operations make up a non-contiguous(不连续的) subsequence(子序列) of the computation history of the program. The portion of this sequence for a particular retainable object pointer for which a specific function execution is directly responsible is the formal local retain history of the object pointer. The corresponding actual sequence executed is the dynamic local retain history.

However, under certain circumstances, ARC is permitted to re-order and eliminate operations in a manner which may alter the overall computation history beyond what is permitted by the general “as if” rule of C/C++ and the restrictions on the implementation of retain and release.

Rationale

Specifically, ARC is sometimes permitted to optimize release operations in ways which might cause an object to be deallocated before it would otherwise be. Without this, it would be almost impossible to eliminate(消除) any retain/release pairs. For example, consider the following code:

id x = _ivar;

[x foo];

If we were not permitted in any event to shorten the lifetime of the object in x, then we would not be able to eliminate this retain and release unless we could prove that the message send could not modify _ivar (or deallocate self). Since message sends are opaque to the optimizer, this is not possible, and so ARC’s hands would be almost completely tied.

ARC makes no guarantees about the execution of a computation history which contains undefined behavior. In particular, ARC makes no guarantees in the presence of race conditions.

ARC may assume that any retainable object pointers it receives or generates are instantaneously(即刻,突如其来的) valid from that point until a point which, by the concurrency(并发性) model of the host language, happens-after the generation of the pointer and happens-before a release of that object (possibly via an aliasing pointer or indirectly due to destruction of a different object).

Rationale

There is very little point in trying to guarantee correctness in the presence of race conditions. ARC does not have a stack-scanning(扫描堆) garbage collector, and guaranteeing the atomicity(原子数) of every load and store operation would be prohibitive(禁止的) and preclude (排除) a vast amount of optimization.

ARC may assume that non-ARC code engages in sensible balancing behavior and does not rely on exact or minimum retain count values except as guaranteed by __strong object invariants or +1 transfer conventions. For example, if an object is provably double-retained and double-released, ARC may eliminate the inner retain and release; it does not need to guard against code which performs an unbalanced release followed by a “balancing” retain.

7.1 object liveness活跃

ARC may not allow a retainable object X to be deallocated at a time T in a computation history if:

  • X is the value stored in a __strong object S with precise lifetime semantics, or
  • X is the value stored in a __strong object S with imprecise lifetime semantics and, at some point after T but before the next store to S, the computation history features a load from S and in some way depends on the value loaded, or
  • X is a value described as being released at the end of the current full-expression and, at some point after T but before the end of the full-expression, the computation history depends on that value.

Rationale

The intent of the second rule is to say that objects held in normal __strong local variables may be released as soon as the value in the variable is no longer being used: either the variable stops being used completely or a new value is stored in the variable.

The intent of the third rule is to say that return values may be released after they’ve been used.

A computation history depends on a pointer value P if it:

  • performs a pointer comparison with P,
  • loads from P,
  • stores to P,
  • depends on a pointer value Q derived via pointer arithmetic(算术) from P (including an instance-variable or field access), or
  • depends on a pointer value Q loaded from P.

Dependency applies only to values derived directly or indirectly from a particular expression result and does not occur merely because a separate pointer value dynamically aliases P. Furthermore, this dependency is not carried by values that are stored to objects.

Rationale

The restrictions on dependency are intended to make this analysis feasible(可行的,可能的) by an optimizer with only incomplete information about a program. Essentially, dependence is carried to “obvious” uses of a pointer. Merely(仅仅) passing a pointer argument to a function does not itself cause dependence, but since generally the optimizer will not be able to prove that the function doesn’t depend on that parameter, it will be forced to conservatively(谨慎的) assume it does.

Dependency propagates(传播) to values loaded from a pointer because those values might be invalidated(使无效) by deallocating the object. For example, given the code __strong id x = p->ivar;, ARC must not move the release of p to between the load of p->ivar and the retain of that value for storing into x.

Dependency does not propagate(传播) through stores of dependent pointer values because doing so would allow dependency to outlive(比某某活的长,活的久) the full-expression which produced the original value. For example, the address of an instance variable could be written to some global location and then freely accessed during the lifetime of the local, or a function could return an inner pointer of an object and store it to a local. These cases would be potentially impossible to reason about and so would basically prevent any optimizations based on imprecise lifetime. There are also uncommon enough to make it reasonable to require the precise-lifetime annotation if someone really wants to rely on them.

Dependency does propagate(传播) through return values of pointer type. The compelling(引人注目的) source of need for this rule is a property accessor which returns an un-autoreleased result; the calling function must have the chance to operate on the value, e.g. to retain it, before ARC releases the original pointer. Note again, however, that dependence does not survive a store, so ARC does not guarantee the continued validity of the return value past the end of the full-expression.

7.2

No object lifttime extentsion

If, in the formal computation history of the program, an object X has been deallocated by the time of an observable side-effect, then ARC must cause X to be deallocated by no later than the occurrence of that side-effect, except as influenced by the re-ordering of the destruction of objects.

Rationale

This rule is intended to prohibit ARC from observably extending the lifetime of a retainable object, other than as specified in this document. Together with the rule limiting the transformation of releases, this rule requires ARC to eliminate retains and release only in pairs.

ARC’s power to reorder the destruction of objects is critical to its ability to do any optimization, for essentially the same reason that it must retain the power to decrease the lifetime of an object. Unfortunately, while it’s generally poor style for the destruction of objects to have arbitrary side-effects, it’s certainly possible. Hence(因此) the caveat(警告).

7.3precise lifetime semantics

In general, ARC maintains an invariant that a retainable object pointer held in a __strong object will be retained for the full formal lifetime of the object. Objects subject to this invariant have precise lifetime semantics.

By default, local variables of automatic storage duration do not have precise lifetime semantics. Such objects are simply strong references which hold values of retainable object pointer type, and these values are still fully subject to the optimizations on values under local control.

Rationale

Applying these precise-lifetime semantics strictly would be prohibitive. Many useful optimizations that might theoretically(理论地) decrease the lifetime of an object would be rendered impossible. Essentially, it promises too much.

A local variable of retainable object owner type and automatic storage duration may be annotated with the objc_precise_lifetime attribute to indicate that it should be considered to be an object with precise lifetime semantics.

Rationale

Nonetheless(尽管如此), it is sometimes useful to be able to force an object to be released at a precise time, even if that object does not appear to be used. This is likely to be uncommon enough that the syntactic weight of explicitly requesting these semantics will not be burdensome, and may even make the code clearer.

8、miscellaneous special methods 混杂的特殊方法

8.1Memory management methods

A program is ill-formed(不规范的) if it contains a method definition, message send, or @selector expression for any of the following selectors:

  • autorelease
  • release
  • retain
  • retainCount

Rationale

retainCount is banned because ARC robs it of consistent semantics. The others were banned after weighing three options for how to deal with message sends:

Honoring them would work out very poorly if a programmer naively or accidentally tried to incorporate code written for manual retain/release code into an ARC program. At best, such code would do twice as much work as necessary; quite frequently, however, ARC and the explicit code would both try to balance the same retain, leading to crashes. The cost is losing the ability to perform “unrooted” retains, i.e. retains not logically corresponding to a strong reference in the object graph.

Ignoring them would badly violate user expectations about their code. While it would make it easier to develop code simultaneously(同时地) for ARC and non-ARC, there is very little reason to do so except for certain library developers. ARC and non-ARC translation units share an execution model and can seamlessly interoperate. Within a translation unit, a developer who faithfully maintains their code in non-ARC mode is suffering all the restrictions of ARC for zero benefit, while a developer who isn’t testing the non-ARC mode is likely to be unpleasantly(令人不愉快的) surprised if they try to go back to it.

Banning them has the disadvantage of making it very awkward(尴尬的) to migrate(移植) existing code to ARC. The best answer to that, given a number of other changes and restrictions in ARC, is to provide a specialized tool to assist users in that migration.

Implementing these methods was banned because they are too integral to the semantics of ARC; many tricks which worked tolerably(相当的,可容忍的) under manual reference counting will misbehave(作弊) if ARC performs an ephemeral extra retain or two. If absolutely required, it is still possible to implement them in non-ARC code, for example in a category; the implementations must obey the semantics laid out elsewhere in this document.

8.2、deallc

A program is ill-formed(不规范的) if it contains a message send or @selector expression for the selector dealloc.

Rationale

There are no legitimate(合法的) reasons to call dealloc directly.

A class may provide a method definition for an instance method named dealloc. This method will be called after the final release of the object but before it is deallocated or any of its instance variables are destroyed. The superclass’s implementation of dealloc will be called automatically when the method returns.(release 方法调用后dealloc方法会被调用)realease —if count == 0 —>dealloc

Rationale

Even though ARC destroys instance variables automatically, there are still legitimate(合法的) reasons to write a dealloc method, such as freeing non-retainable resources. Failing to call [super dealloc] in such a method is nearly always a bug. Sometimes(在arc里面调用[super dealloc]是非法的), the object is simply trying to prevent itself from being destroyed, but dealloc is really far too late for the object to be raising such objections. Somewhat more legitimately(合法地), an object may have been pool-allocated and should not be deallocated with free; for now, this can only be supported with a dealloc implementation outside of ARC. Such an implementation must be very careful to do all the other work that NSObject’s dealloc would, which is outside the scope of this document to describe.

The instance variables for an ARC-compiled class will be destroyed at some point after control enters the dealloc method for the root class of the class. The ordering of the destruction of instance variables is unspecified, both within a single class and between subclasses and superclasses.

Rationale

The traditional, non-ARC pattern for destroying instance variables is to destroy them immediately before calling [super dealloc]. Unfortunately, message sends from the superclass are quite capable of(很有可能) reaching methods in the subclass, and those methods may well read or write to those instance variables. Making such message sends from dealloc is generally discouraged(气馁的), since the subclass may well rely on other invariants(不变的) that were broken during dealloc, but it’s not so inescapably(不可避免的) dangerous that we felt comfortable calling it undefined behavior. Therefore we chose to(选择) delay destroying the instance variables to a point at which message sends are clearly disallowed: the point at which the root class’s deallocation routines take over(接管).

In most code, the difference is not observable(显著的). It can, however, be observed if an instance variable holds a strong reference to an object whose deallocation will trigger a side-effect(副作用) which must be carefully ordered with respect to the destruction of the super class. Such code violates(违反) the design principle that semantically(语义的) important behavior should be explicit(清楚的). A simple fix is to clear the instance variable manually during dealloc; a more holistic(整体的,全盘的) solution is to move semantically important side-effects out of dealloc and into a separate teardown phase which can rely on working with well-formed objects.

8.3、autoreleasepool

To simplify the use of autorelease pools, and to bring them under the control of the compiler, a new kind of statement is available in Objective-C. It is written @autoreleasepool followed by a compound-statement(混合语句), i.e. by a new scope delimited by curly braces. Upon entry to this block, the current state of the autorelease pool is captured. When the block is exited normally, whether by fallthrough or directed control flow (such as return or break), the autorelease pool is restored to the saved state, releasing all the objects in it. When the block is exited with an exception, the pool is not drained.

@autoreleasepool may be used in non-ARC translation units, with equivalent (等价集合)semantics.

A program is ill-formed if it refers to the NSAutoreleasePool class.

Rationale

Autorelease pools are clearly important for the compiler to reason about, but it is far too much to expect the compiler to accurately reason about control dependencies(依赖,相关性) between two calls. It is also very easy to accidentally forget to drain an autorelease pool when using the manual API, and this can significantly inflate(使充气,使膨胀) the process’s high-water-mark. The introduction of a new scope is unfortunate but basically required for sane interaction with the rest of the language. Not draining the pool during an unwind(放松) is apparently(显然的,表面上的) required by the Objective-C exceptions implementation.

8.4 self

The self parameter variable of an Objective-C method is never actually retained by the implementation. It is undefined behavior, or at least dangerous, to cause an object to be deallocated during a message send to that object.

To make this safe, for Objective-C instance methods self is implicitly const unless the method is in the init family. Further, self is always implicitly(含蓄的) const within a class method.

Rationale

The cost of retaining self in all methods was found to be prohibitive(禁止的), as it tends to be live across calls, preventing the optimizer from proving that the retain and release are unnecessary — for good reason, as it’s quite possible in theory to(在理论上) cause an object to be deallocated during its execution without this retain and release. Since it’s extremely uncommon to actually do so, even unintentionally(无意的,非故意的), and since there’s no natural way for the programmer to remove this retain/release pair otherwise (as there is for other parameters by, say, making the variable __unsafe_unretained), we chose to make this optimizing assumption(假定,设想) and shift some amount of risk to the user.

8.5、

Fast enumeration iteration variables

If a variable is declared in the condition of an Objective-C fast enumeration loop, and the variable has no explicit ownership qualifier, then it is qualified with const__strong and objects encountered during the enumeration are not actually retained.

Rationale

This is an optimization made possible because fast enumeration loops promise to keep the objects retained during enumeration, and the collection itself cannot be synchronously(同步的) modified. It can be overridden by explicitly qualifying the variable with __strong, which will make the variable mutable again and cause the loop to retain the objects it encounters.

Blocks

The implicit const capture variables created when evaluating(评估) a block literal expression have the same ownership semantics as the local variables they capture. The capture is performed by reading from the captured variable and initializing the capture variable with that value; the capture variable is destroyed when the block literal is, i.e. at the end of the enclosing scope.

The inference rules apply equally to __block variables, which is a shift in semantics from non-ARC, where __block variables did not implicitly(含蓄的) retain during capture.

__block variables of retainable object owner type are moved off the stack by initializing the heap copy with the result of moving from the stack copy.

With the exception of retains done as part of initializing a __strong parameter variable or reading a __weak variable, whenever these semantics call for retaining a value of block-pointer type, it has the effect of a Block_copy. The optimizer may remove such copies when it sees that the result is used only as an argument to a call.

8.6 Exceptions

By default in Objective C, ARC is not exception-safe for normal releases:

  • It does not end the lifetime of __strong variables when their scopes are abnormally(反常地) terminated by an exception.
  • It does not perform releases which would occur at the end of a full-expression if that full-expression throws an exception.

A program may be compiled with the option -fobjc-arc-exceptions in order to enable these, or with the option -fno-objc-arc-exceptions to explicitly disable them, with the last such argument “winning”.

Rationale

The standard Cocoa convention is that exceptions signal programmer error and are not intended to be recovered from. Making code exceptions-safe by default would impose severe runtime and code size penalties(处罚) on code that typically does not actually care about exceptions safety. Therefore, ARC-generated code leaks by default on exceptions, which is just fine if the process is going to be immediately terminated anyway. Programs which do care about recovering from exceptions should enable the option.

In Objective-C++, -fobjc-arc-exceptions is enabled by default.

Rationale

C++ already introduces pervasive(普遍的) exceptions-cleanup code of the sort that ARC introduces. C++ programmers who have not already disabled exceptions are much more likely to actual require exception-safety.

ARC does end the lifetimes of __weak objects when an exception terminates their scope unless exceptions are disabled in the compiler.

Rationale

The consequence of a local __weak object not being destroyed is very likely to be corruption of the Objective-C runtime, so we want to be safer here. Of course, potentially massive leaks are about as likely to take down the process as this corruption is if the program does try to recover from exceptions.

8.7 Interior pointers(内部指针)

An Objective-C method returning a non-retainable pointer may be annotated with the objc_returns_inner_pointer attribute to indicate that it returns a handle to the internal data of an object, and that this reference will be invalidated if the object is destroyed. When such a message is sent to an object, the object’s lifetime will be extended(延伸的) until at least the earliest of:。

   the last use of the returned pointer, or any pointer derived from it, in the calling function or

  • the autorelease pool is restored to a previous state.

Rationale

Rationale: not all memory and resources are managed with reference counts; it is common for objects to manage private resources in their own, private way. Typically these resources are completely encapsulated within the object, but some classes offer their users direct access for efficiency. If ARC is not aware of methods that return such “interior” pointers, its optimizations can cause the owning object to be reclaimed too soon. This attribute informs ARC that it must tread(踏) lightly.

The extension rules are somewhat intentionally(故意的) vague(含糊的). The autorelease pool limit is there to permit a simple implementation to simply retain and autorelease the receiver. The other limit permits some amount of optimization. The phrase “derived from” is intended to encompass the results both of pointer transformations, such as casts and arithmetic(算术算法), and of loading from such derived pointers; furthermore, it applies whether or not such derivations are applied directly in the calling code or by other utility code (for example, the C library routine strchr). However, the implementation never need account for uses after a return from the code which calls the method returning an interior pointer.

As an exception, no extension is required if the receiver is loaded directly from a __strong object with  precise lifetime semantics.

Rationale

Implicit autoreleases carry the risk of significantly inflating memory use, so it’s important to provide users a way of avoiding these autoreleases. Tying this to precise lifetime semantics is ideal, as for local variables this requires a very explicit annotation, which allows ARC to trust the user with good cheer.

 

8.8

C retainable pointer types

A type is a C retainable pointer type if it is a pointer to (possibly qualified) void or a pointer to a (possibly qualifier) struct or class type.

Rationale

ARC does not manage pointers of CoreFoundation type (or any of the related families of retainable C pointers which interoperate(交互操作) with Objective-C for retain/release operation). In fact, ARC does not even know how to distinguish these types from arbitrary C pointer types. The intent of this concept is to filter(虑过) out some obviously non-object types while leaving a hook for later tightening if a means of exhaustively(耗尽一切的) marking CF types is made available.

 

Auditing of C retainable pointer interfaces

[beginning Apple 4.0, LLVM 3.1]

A C function may be marked with the cf_audited_transfer attribute to express that, except as otherwise marked with attributes, it obeys(服从) the parameter (consuming vs. non-consuming) and return (retained vs. non-retained) conventions for a C function of its name, namely:

  • A parameter of C retainable pointer type is assumed to not be consumed unless it is marked with the cf_consumed attribute, and
  • A result of C retainable pointer type is assumed to not be returned retained unless the function is either marked cf_returns_retained or it follows the create/copy naming convention and is not marked cf_returns_not_retained.

A function obeys the create/copy naming convention if its name contains as a substring:

  • either “Create” or “Copy” not followed by a lowercase letter, or
  • either “create” or “copy” not followed by a lowercase letter and not preceded by any letter, whether uppercase or lowercase.

A second attribute, cf_unknown_transfer, signifies(表示) that a function’s transfer(转移) semantics cannot be accurately captured using any of these annotations. A program is ill-formed if it annotates the same function with both cf_audited_transfer and cf_unknown_transfer.

A pragma is provided to facilitate(促进,帮助) the mass annotation of interfaces:

#pragma clang arc_cf_code_audited begin

...

#pragma clang arc_cf_code_audited end

All C functions declared within the extent of this pragma are treated as if annotated with the cf_audited_transfer attribute unless they otherwise have the cf_unknown_transfer attribute. The pragma is accepted in all language modes. A program is ill-formed(不规范的) if it attempts to change files, whether by including a file or ending the current file, within the extent of this pragma.

It is possible to test for all the features in this section with __has_feature(arc_cf_code_audited).

Rationale

A significant inconvenience in ARC programming is the necessity of interacting with APIs based around C retainable pointers. These features are designed to make it relatively easy for API authors to quickly review and annotate their interfaces, in turn improving the fidelity(保真度) of tools such as the static analyzer and ARC. The single-file restriction on the pragma is designed to eliminate the risk of accidentally annotating some other header’s interfaces.

9.0

Runtime support 

This section describes the interaction between the ARC runtime and the code generated by the ARC compiler. This is not part of the ARC language specification; instead, it is effectively a language-specific ABI supplement(增补,补充), akin(类似的) to the “Itanium” generic(一般的) ABI for C++.

Ownership qualification does not alter the storage requirements for objects, except that it is undefined behavior if a __weak object is inadequately(不断的) aligned for an object of type id. The other qualifiers may be used on explicitly under-aligned memory.

The runtime tracks __weak objects which holds non-null values. It is undefined behavior to direct modify a __weak object which is being tracked by the runtime except through an objc_storeWeak,objc_destroyWeak , or objc_moveWeak call.

The runtime must provide a number of new entrypoints(进入点) which the compiler may emit, which are described in the remainder of this section.

Rationale

Several of these functions are semantically equivalent to a message send; we emit(发出,发射) calls to C functions instead because:

  • the machine code to do so is significantly smaller,
  • it is much easier to recognize the C functions in the ARC optimizer, and
  • a sufficient sophisticated runtime may be able to avoid the message send in common cases.

Several other of these functions are “fused” operations which can be described entirely(完全的) in terms of other operations. We use the fused operations primarily as a code-size optimization, although in some cases there is also a real potential for avoiding redundant(多余的) operations in the runtime.

id objc_autorelease(id value);

Precondition(前提条件): value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it adds the object to the innermost(内心的) autorelease pool exactly as if the object had been sent the autoreleasemessage.

Always returns value.(把值放入池子,自动释放)

void objc_autoreleasePoolPop(void *pool);

Precondition: pool is the result of a previous call to objc_autoreleasePoolPush on the current thread(池子是autoreleasePoolPush的结果), where neither pool nor any enclosing pool have previously been popped.

Releases all the objects added to the given autorelease pool and any autorelease pools it encloses, then sets the current autorelease pool to the pool directly enclosing pool.

void *objc_autoreleasePoolPush(void);

Creates a new autorelease pool that is enclosed by the current pool, makes that the current pool, and returns an opaque(不透明的) “handle” to it.

Rationale

While the interface is described as an explicit hierarchy(层级) of pools, the rules allow the implementation to just keep a stack of objects, using the stack depth as the opaque pool handle.

id objc_autoreleaseReturnValue(id value);

Precondition(前提): value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it makes a best effort to hand off ownership of a retain count on the object to a call toobjc_retainAutoreleasedReturnValue for the same object in an enclosing call frame. If this is not possible, the object is autoreleased as above.

Always returns value.

void objc_copyWeak(id *dest, id *src);

Precondition: src is a valid pointer which either contains a null pointer or has been registered as a __weak object. dest is a valid pointer which has not been registered as a __weak object.

dest is initialized to be equivalent to src, potentially registering it with the runtime. Equivalent to the following code:

void objc_copyWeak(id *dest, id *src) {

  objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));

}

Must be atomic with respect to calls to objc_storeWeak on src.

void objc_destroyWeak(id *object);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.

object is unregistered as a weak object, if it ever was. The current value of object is left unspecified; otherwise, equivalent to the following code:

void objc_destroyWeak(id *object) {

  objc_storeWeak(object, nil);

}

Does not need to be atomic with respect to calls to objc_storeWeak on object.

id objc_initWeak(id *object, id value);

Precondition(前提): object is a valid pointer which has not been registered as a __weak object. value is null or a pointer to a valid object.

If value is a null pointer or the object to which it points has begun deallocation, object is zero-initialized. Otherwise, object is registered as a __weak object pointing to value. Equivalent to the following code:

id objc_initWeak(id *object, id value) {

  *object = nil;

  return objc_storeWeak(object, value);

}

Returns the value of object after the call.

Does not need to be atomic with respect to calls to objc_storeWeak on object.

id objc_loadWeak(id *object);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.

If object is registered as a __weak object, and the last value stored into object has not yet been deallocated or begun deallocation, retains and autoreleases that value and returns it. Otherwise returns null. Equivalent to the following code:

id objc_loadWeak(id *object) {

  return objc_autorelease(objc_loadWeakRetained(object));

}

Must be atomic with respect to calls to objc_storeWeak on object.

Rationale

Loading weak references would be inherently prone to race conditions without the retain.

id objc_loadWeakRetained(id *object);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.

If object is registered as a __weak object, and the last value stored into object has not yet been deallocated or begun deallocation, retains that value and returns it. Otherwise returns null.

Must be atomic with respect to calls to objc_storeWeak on object.

void objc_moveWeak(id *dest, id *src);

Precondition: src is a valid pointer which either contains a null pointer or has been registered as a __weak object. dest is a valid pointer which has not been registered as a __weak object.

dest is initialized to be equivalent to src, potentially registering it with the runtime. src may then be left in its original state, in which case this call is equivalent to objc_copyWeak, or it may be left as null.

Must be atomic with respect to calls to objc_storeWeak on src.

void objc_release(id value);

Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it performs a release operation exactly as if the object had been sent the release message.

id objc_retain(id value);

Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it performs a retain operation exactly as if the object had been sent the retain message.

Always returns value.

id objc_retainAutorelease(id value);

Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it performs a retain operation followed by an autorelease operation. Equivalent to the following code:

id objc_retainAutorelease(id value) {

  return objc_autorelease(objc_retain(value));

}

Always returns value.

id objc_retainAutoreleaseReturnValue(id value);

Precondition: value is null or a pointer to a valid object.(值可以是null或者指向一个有效对象的指针)

If value is null, this call has no effect. Otherwise, it performs a retain operation followed by the operation described in objc_autoreleaseReturnValue. Equivalent to the following code:(如果value是空的,这调用没影响,否则,产生的效果跟下面的方法一样)

id objc_retainAutoreleaseReturnValue(id value) {

  return objc_autoreleaseReturnValue(objc_retain(value));

}

Always returns value.

id objc_retainAutoreleasedReturnValue(id value);(注意这方法跟上面方法的区别,这里是autoreleased,上面是autorelease)

Precondition: value is null or a pointer to a valid object.

If value is null, this call has no effect. Otherwise, it attempts to accept a hand off(一只手从) of a retain count from a call to objc_autoreleaseReturnValue on value in a recently-called function or something it calls. If that fails, it performs a retain operation exactly like objc_retain.

Always returns value.

id objc_retainBlock(id value);

Precondition: value is null or a pointer to a valid block object.

If value is null, this call has no effect. Otherwise, if the block pointed to by value is still on the stack, it is copied to the heap and the address of the copy is returned. Otherwise a retain operation is performed on the block exactly as if it had been sent the retain message.

id objc_storeStrong(id *object, id value);

Precondition: object is a valid pointer to a __strong object which is adequately(充分地) aligned for a pointer. value is null or a pointer to a valid object.

Performs the complete sequence for assigning to a __strong object of non-block type [*]. Equivalent to the following code:

void objc_storeStrong(id *object, id value) {

  id oldValue = *object;

  value = [value retain];

  *object = value;

  [oldValue release];

}

[*]

This does not imply that a __strong object of block type is an invalid argument to this function. Rather it implies that an objc_retain and not an objc_retainBlock operation will be emitted if the argument is a block.

id objc_storeWeak(id *object, id value);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object. value is null or a pointer to a valid object.

If value is a null pointer or the object to which it points has begun deallocation, object is assigned null and unregistered as a __weak object. Otherwise, object is registered as a __weak object or has its registration updated to point to value.

Returns the value of object after the call.

第三次学习:

https://mp.weixin.qq.com/s/DOK6WooYiwYCAxSJ-5k0Wg

 

1、有四种修饰符号

__strong修饰符,__weak修饰符,__unsafe_unretained__修饰符,__autoreleasing修饰符

2、id __strong obj = [[NSObject alloc] init];

id __attribute__((objc_ownership(strong))) obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));

3、会调用这些方法:

id obj = objc_msgSend(NSObject, @selector(alloc));

objc_msgSend(obj,selector(init));

objc_release(obj);

4、 id __strong obj = [NSMutableArray array];

5、转化为:id __attribute__((objc_ownership(strong))) array = ((NSMutableArray *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("array"));

6、id obj = objc_msgSend(NSMutableArray, @selector(array));

objc_retainAutoreleasedReturnValue(obj);

objc_release(obj);

与之前对象会持有自己的情况不同,这里多了一个objc_retainAutoreleasedReturnValue函数

7、这属于LLVM编译器的一个优化。objc_retainAutoreleasedReturnValue函数是用于自己持有(retain)对象的函数,它持有的对象应为返回注册在autoreleasepool中对象的方法或者是函数的返回值。

在ARC中原本对象生成之后是要注册到autoreleasepool中,但是调用了objc_autoreleasedReturnValue 之后,紧接着调用了 objc_retainAutoreleasedReturnValue,objc_autoreleasedReturnValue函数会去检查该函数方法或者函数调用方的执行命令列表,如果里面有objc_retainAutoreleasedReturnValue()方法,那么该对象就直接返回给方法或者函数的调用方。达到了即使对象不注册到autoreleasepool中,也可以返回拿到相应的对象。

8、{

    id __weak obj = strongObj;

}

转换为:id __attribute__((objc_ownership(none))) obj1 = strongObj;

id obj ;

objc_initWeak(&obj,strongObj);

objc_destoryWeak(&obj);

9、weak原理

id objc_initWeak(id *object, id value) {   

    *object = nil; 

    return objc_storeWeak(object, value);

}

void objc_destroyWeak(id *object) { 

    objc_storeWeak(object, nil);

}

10、由于笔者一直很崇拜AFNetWorking的作者,这个库里面的代码都很整洁,里面各方面的代码都可以当做代码范本来阅读。遇到不懂疑惑的,都要深究,肯定会有收获。这里就是一处,平时我们的写法是不带__的,AFN里面用这种写法有什么特殊的用途么?

11、#define WEAKSELF typeof(self) __weak weakSelf = self; 这是我们平时的写法。。

12、为什么iOS的masonry中的self不会循环引用。

13、objc_initWeak和objc_destroyWeak函数都会去调用objc_storeWeak函数,唯一不同的是调用的入参不同,一个是value,一个是nil.

14、id objc_storeWeak(id * object, id value)

object is valid pointer which either contains a null pointer or has been registered as a __weak object value.

object要么是一个空指针,要么就是一个weak 对象值。

15、由于weak表也是用hash table 实现的,所以objc_storeWeak函数就把第一个入参的变量地址注册到weak表中,然后根据二个参数决定是否移除。如果第二个参数为零,那么就把__weak变量从weak表中删除记录,并从引用计数表中删除对应的键值记录。

16、所以如果__weak引用的原对象如果被释放了,那么对应的__weak对象就会被指为nil.原来主要是就是通过objc_storeWeak函数实现的。

17、

 

 

深入研究block捕获外部变量和__block实现原理。

1、一句话形容blocks,block是带有自动变量的匿名函数。

2、从结构图中很容易看到isa,所以oc处理Block是按照对象来处理的。

3、isa常见的就是_NSConcreteStackBlock,_NSConcreteMallocBlock,_NSConreteGloablBlock三种

4、为了研究编译器的实现原理,我们需要使用clang命令。clang命令可以将Objective-C的源代码改写成C/C++语言的,借此可以研究block中各个特性的源代码实现方式。

命令是:clang -rewrite-objc block.c

5、自动变量以值传递方式传递到Block的构造函数里面去的。Block只捕获Block中会用到的变量。由于只捕获了自动变量的值,并非内存地址,多以Block内部不能改变自动变量的值。Block捕获的外部变量可以改变值的事静态变量,静态全局变量,全局变量。

6、总结一下在block中改变变量值有2种方式,一是传递内存地址指针到block中,二十改变存储方式(__block)

7、_NSConcreteStackBlock

只要到外部局部变量、成员属性变量,且没有强指针引用的block都是StackBlock。StackBlock的生命周期由系统控制的,一旦返回之后,就被系统销毁了。

8、NSConcreteMallocBlock

有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock,没有强指针引用即销毁,生命周期由程序员控制。

9、NSconcreteGlobalBlock

没有用到外界变量或只用到全局变量、静态变量的block为NSConcreteGlobalBlock,生命周期从创建应用程序结束。

10、只有到全局变量、静态变量的block也可以是_NSConcreteGlobalBlock

11、__NSConcreteStackBlock是不持有对象的

12、__NSConcreteMallocBlock是持有对象的

13、__NSConcreteGlabalBlock也不持有对象

14、由于__NSConcreteStackBlock所属的变量域一旦结束,那么该block就会被销毁。在ARC环境下,编译器自动的判断,把Block自动的从栈copy到堆

15、手动调用copy;block是函数的返回值;block被强引用,block被赋值给__strong或者id类型;调用系统API入参中含有usingBlock的方法。以上四种情况,系统都会默认调用copy方法把block复制。

16、copy函数把Block从栈上拷贝到堆上,dispose函数是把堆上的函数在废弃的时候销毁掉。

17、block其实就是一个对象(也可以说是一个结构体吗),它有自己的变量,自己的方法,这个

这个对象还分为三种,栈block,全局block,和堆block

18、所谓的持有就是看有没有进行retain 或者copy等增加引用计数的操作

19、Block中__block的实现原理

struct __Block_byref_i_0 {

  void *__isa;

__Block_byref_i_0 *__forwarding;

 int __flags;

 int __size;

 int i;

};

 

从源码我们能发现,带有__block的变量也被转化成了一个结构体__Block_byref_i_0,这个结构体有5个成员变量。第一个是isa指针,第二个是指向自身类型的__forwarding指针,第三个是一个标记flag,第四个是它的大小,第五个是变量值,名字和变量名同名。

20、在MRC环境下,__block根本不会对指针所指向的对象执行copy操作,而只是把指针进行复制。在ARC环境下,对于生明为__block的外部对象,在block内部会进行retain,以至于在block环境内能安全的引用外部对象,所以才会产生循环引用。

21、关于Block捕获外部变量有很多用途,用途也很广,只有弄清了捕获变量和持有的变量的概念以后,之后才能清楚的解决Block循环引用的问题。

22、关于Block捕获外部变量有很多用途,用途也很广,只有弄清了捕获变量和持有的变量的概念以后,之后才能清楚的解决Block循环引用的问题。

再次回到文章开头,5种变量,自动变量,函数参数 ,静态变量,静态全局变量,全局变量,如果严格的来说,捕获是必须在Block结构体__main_block_impl_0里面有成员变量的话,Block能捕获的变量就只有带有自动变量和静态变量了。捕获进Block的对象会被Block持有。

23、自动变量的值,被copy进了Block,不带__block的自动变量只能只能在里面被访问,并不能改变值。

24、带__block的自动变量和静态变量就是直接地址访问。所以在BLock里面可以直接改变量的值。

25、而剩下的静态全局变量,全局变量,函数参数,也是可以在直接在Block中改变变量值的,但是他们并没有变成Block结构体__main_block_impl_0的成员变量,因为他们的作用域大,所以可以直接更改他们的值。

值得注意的是,静态全局变量,全局变量,函数参数他们并不会被Block持有,也就是说不会增加retainCount值。

第四次学习:clang

参考链接:

https://www.cnblogs.com/wzk89/p/4650637.html

 

第五次学习:

(一)特殊的写法

1、- (void)testAction {

    for (int i = 0; i < 4; i++) {

        ///activity info

        [self.recommendViewModel requestDiscoverActivityDataCompletion:^(BOOL succeed, NSString *errorMsg) {

        }];

    }

}

这么写每次传入的block指针是一样的

与推荐里面的ready和current不一样,因为ready和current传入的参数是不一样的

2、当我变了参数后,打印的block都变了,神奇啊。这个就是ready和current一样的了

- (void)testAction{

    for (int i = 0; i< 4; i++) {

        ///瀑布流

        @weakify(self);

        NSDictionary *parameter = @{@"currentPage":@(i),

                                     @"currentPageSize":@(15),

                                     @"currentTime":[NSString calculateTimeToMillisecond:self.date],

                                     @"deviceId":[[UIDevice currentDevice] mdf_deviceUDID],

                                     @"sunburnUuid":@"",@"tabId":@(self.tabModel.tabId),

                                     @"userId":@([[UserInfoManager getContentID] integerValue])};

        [self.feedInfoViewModel requestDiscoverFeedDataParameter:parameter feedDataCompletion:^(BOOL succeed, NSString *errorMsg) {

        }];

    }

打印输入的block

2019-09-27 11:00:01.653429+0800 Secoo-iPhone[31175:2931243] print secoo T <__NSMallocBlock__: 0x110e600e0>

2019-09-27 11:00:01.704964+0800 Secoo-iPhone[31175:2931243] print secoo T <__NSMallocBlock__: 0x10c0500a0>

2019-09-27 11:00:05.663455+0800 Secoo-iPhone[31175:2931243] print secoo T <__NSMallocBlock__: 0x111ca1830>

2019-09-27 11:00:05.685429+0800 Secoo-iPhone[31175:2931243] print secoo T <__NSMallocBlock__: 0x111f869a0>

3所以MRC中Block都需要用copy来修饰,而在ARC中用copy修饰只是沿用了MRC的习惯,此时用copy和strong效果是相同的。

4、同样代码这么写和那么些都没问题

(1)

for (int i = 0; i < appMenuVcDataArr.count; i++) {

        MenuAttributeModel *menuModel = appMenuVcDataArr[i];

        [[SDWebImageManager sharedManager]

         loadImageWithURL:[NSURL URLWithString:menuModel.notOptIconAddress]

         options:0

         progress:nil

         completed:^(UIImage * _Nullable normalImage, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {

             [[SDWebImageManager sharedManager]

              loadImageWithURL:[NSURL URLWithString:menuModel.optIconAddress]//这里的menuModel不会因为外面的循环乱变化

              options:0

              progress:nil

              completed:^(UIImage * _Nullable selectedImage, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {

                               //这么写normalImage 和 selectedImage图片能跟i一一配对

                  });

              }];

         }];

(2)

for (int i = 0; i <self.videoModel.contentGoods.count; i++) {

       NSString *imageUrl = goodsInfoModel.imgUrl;

        [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:imageUrl] options:SDWebImageDownloaderUseNSURLCache progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {

            [[SDImageCache sharedImageCache] storeImage:image forKey:imageUrl completion:nil];

        }];

    }

这么写也是同理,不会有问题,以上两个例子都不会因为异步和循环而匹配对应的i的值。

(二)__block事实和现象

https://www.jianshu.com/p/d96d27819679

1、只要加了__block这个变量,并定义了一个block,这个变量的地址就会变了,到堆区

block里面变化数组,不用加__block,待验证

2、第一条,与这个block有没有执行无关

3、如果block里面没有改变值,那么a变量的地址还是不变的,不论block有没有调用

4、__block的作用,就是就是将变量赋值到堆上面去了

5、上面介绍了Block也就是Block_layout的源码,Block_private.h中还有定义了一个结构体Block_byref,变量在被__block修饰时由编译器来生成,结构如下:

6、以上就是_NSConcreteStackBlock转换成_NSConcreteMallocBlock的过程,下面按步解释每一步的作用。

7、存在于全局区,内存在程序结束后由系统回收

内存由编译器控制。很牛逼,编译器和系统是什么呢

8、作用域是个好东西

作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。

 

第六次学习

[object reqestABlock:comption]

如果没有回调,很可能是object为空

之前以为afnetworking在判断网络不明时,不会回调,这是错的,如果没网,必然会失败回调。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值