├── .gitignore ├── Articles ├── ASCII-Unicode-UTF8.md ├── CGSize-CGPoint.md ├── Class-Cluster-NSDictionary.md ├── Danger of Method Swizzling.md ├── Dealloc.md ├── Install-PhonyDebugger.md ├── Little-code-block.md ├── Touch-events-outside.md ├── When-layoutsubviews-get-called.md ├── common-debug-tips.md ├── fucking-clang-warnings.md ├── lock-benchmark.md └── viweDidLoad-viewWillAppear-in-one-event-loop.md ├── Demos └── DeallocDemo │ ├── DeallocDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── DeallocDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── ViewController.h │ ├── ViewController.m │ └── main.m │ └── DeallocDemoTests │ └── DeallocDemoTests.m ├── README.md └── images ├── connected.jpg ├── hit-testing.jpg ├── inside.jpg ├── lldb-demo-1.png ├── localhost.png ├── lock-demo.png ├── symbolic-breakpoint-demo.jpg └── xode-debug-demo1.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # OS generated files # 21 | ###################### 22 | .DS_Store 23 | .DS_Store? 24 | ._* 25 | 26 | -------------------------------------------------------------------------------- /Articles/ASCII-Unicode-UTF8.md: -------------------------------------------------------------------------------- 1 | 2 | ASCII GB2312 Unicode UTF-8 等常见字符编码方式 3 | --- 4 | 5 | 在开发过程中,经常要碰到各种字符集/编码方式,总结一下由来、联系、区别。 6 | 7 | 1. > ASCII,全称American Standard Code for Information Interchange。很久前一群人决定用8个可以开合的晶体管来组合不同的状态,并称这8个晶体管的开关状态为**_字节_**。后来有了一些可以处理这些字节的机器,并用字节来组合出很多状态,这种机器被称为**_计算机_**。8个字节可以表示256种不同的状态,并约定机器在某些状态下做出某些反应,如当终端遇到0x10就换行,遇到0x1b打印机就打印反白的字等等,于是把0x20以下的字节状态称为_**控制码**。_并把空格、标点符号、数字、大写英文字母、小写英文字母分别用连续的字节状态表示,一直编到了127号,这样就可以用不同字节来存储英文文字了,这个编码方案被称为ANSI(美国国家标准协会)的_**ASCII码**_。此时,世界上的所有的计算机都用ASCII方案来保存英文文字。 8 | 9 | 2. > 可是并不是全世界都用英文的,所以随着世界上更多的国家开始使用计算机,越来越多人发现ASCII无法满足他们要存储其他文字的需求。于是他们把127号之后的没有被ASCII使用的位用来表示这些新的字母、符号、横线、竖线等,一直把序号编到了255。从128到255的这些字符集被称为**_扩展字符集。_** 10 | 11 | 3. > 后来中国人想存汉字,可是已经没有可用的字节状态了,而且常用汉字6000多个,就算8位的字节全都用来表示汉字也不够。国人直接把127号以后的扩展字符集全部去取消,然后规定一个小雨127的字符的意义与ASCII中一样,但两个大于127的字符连在一起就表示一个汉字,前面一个字节为_**高字节**_,从0xA1到0xF7;后面一个字节为_**低字节**_,从0xA1到0xFE。这样就可以组合大约7000多个简体汉字了。且在这些编码里把数学符号、希腊字母、日文的假名都编进去了。并对ASCII中本来就有的数字、标点、字母都重新编了两个字节长的编码,这就是我们总可以看到的**_全角字符_**,而原来127以下的那些就是_**半角字符**_。这种编码方式被规定为GB2312,可以看出GB2312是对ASCII的中文扩展,其中GB就是“国标”的拼音的缩写。 12 | 13 | 4. > 显然,汉字太多了,尤其有些人的名字里还有生僻字,打不出自己名字怎么行呢,于是,我们把GB2312的限制再放开一些,刚才说GB2312后面一个字节(低字节)为127之后才认为是汉字,现在把这个规定取消,只要高字节是127之后,那就认为是一个汉字的开始了。这个扩展之后的结果就是GBK标准。GBK包括了GB2312的所有内容,同时还增加了2万个新的汉字(含繁体字)和符号。 14 | 15 | 5. > 中国56个民族的语言当然不是汉字可以囊括的,为增加少数名族的文字,又把GBK扩展成了GB18030。 16 | 17 | 6. > 这一系列的中文编码标准被统称为DBCS(Double Byte Character Set 双字节字符集),其特点就是双字节长的中文字符和一字节长的英文字符并存于同一套编码方案,这也是为什么一个汉字算两个英文字符的原因。于是为了支持中文处理,程序员们需要必须注意字串里的每一个字节的值。 18 | 19 | 7. > 当然,除了中文外还有很多其他非英文的语言,于是世界各地的不同语言的国家纷纷自己搞一套标准,谁也不兼容谁。甚至隔海相望的台湾也采用了不同的DBCS编码方案(如繁体中文Big5),当时为了可以处理汉字,必须在计算机上装一个“汉卡”才行。联想柳传志找来中科院的倪光南做了“联想式汉卡”、史玉柱后来也开发了一个汉卡系统,并且都因此而起家。 20 | 21 | 8. > ISO(国际标准化组织)决定着手解决这个问题,办法简单而粗暴,抛开所有地方性编码,重新制定包括所有文字、所有字母、符号的编码,叫做Unicode(Universal Multiple-Octet Coded Character Set,简称UCS,俗称Unicode)。这时候的计算机的存储容量极大地发展了,空间再也不成问题,于是ISO直接规定必须用两个字节来进行字符编码,也就是统一用16位进行编码。对于ASCII中的字符,Unicode保持其原编码值不变,只是将其长度由原来8位扩展为16位(高8位补0)。 22 | 23 | 9. > 正如上面所说的,Unicode在制定的时候没有想过要跟任何一种现有的编码方案保持兼容,所以GBK与Unicode在汉字内码的编排上完全是不一样的,没有一种简单的算法可以把文本内容从Unicode编码和另一种编码进行转换,这种转换只能查表。 24 | 25 | 10. > UCS(Unicode的简称)还有4字节版,可以组合出21亿个不同的字符,叫UCS-4。 26 | 27 | 11. > Unicode解决了很多公司的难题,终于可以不用为了进入某个地区的市场而额外处理文字的编码问题了。Windows NT开始,微软把操作系统中的核心代码都改成了Unicode方式工作的版本,从而无需加装本土语言系统就可以显示各国字符了。 28 | 29 | 12. > 随着计算机网络的发展,Unicode如何在网络上传输成了必须考虑的问题。于是有了面向传输的众多UTF(UCS Transfer Format)标准的出现,而UTF8(8-bit Unicode Transformation Format)就是以每次8个位传输数据,是一种针对Unicode的可变长度的字符编码,也是一种前缀码,可以用来表示Unicode中的任何字符,且其编码中的第一个字节仍与ASCII兼容,Unicode形式的ASCII字符经过UTF8编码后得到的长度为一个字节,且意义与ASCII中一致。其余Unicode字符经过UTF8编码后至少2个字节。UTF8编码有几个显著的优势,其一是兼容ASCII码;其二是乱码不会扩散,而GB2312在丢失一字节等情况下会造成后续所有文字全部变成乱码;其三是UTF8可以是一个更大的字符集。 30 | 31 | -------------------------------------------------------------------------------- /Articles/CGSize-CGPoint.md: -------------------------------------------------------------------------------- 1 | ### CGSize, CGPoint, CGRect 的写法 2 | --- 3 | 4 | #### 几个结构体定义 5 | 6 | ``` 7 | // CGGeometry.h 8 | 9 | /* Points. */ 10 | 11 | struct CGPoint { 12 | CGFloat x; 13 | CGFloat y; 14 | }; 15 | typedef struct CGPoint CGPoint; 16 | 17 | /* Sizes. */ 18 | 19 | struct CGSize { 20 | CGFloat width; 21 | CGFloat height; 22 | }; 23 | typedef struct CGSize CGSize; 24 | 25 | 26 | /* Rectangles. */ 27 | 28 | struct CGRect { 29 | CGPoint origin; 30 | CGSize size; 31 | }; 32 | typedef struct CGRect CGRect; 33 | ``` 34 | 35 | 36 | #### 常见写法 37 | 38 | ``` 39 | CGPoint point = CGPointMake(0, 0); 40 | CGSize size = CGSizeMake(10, 20); 41 | CGRect rect = CGRectMake(0, 0, 10, 20); 42 | 43 | ``` 44 | 45 | #### 但既然是普通结构体,还可以这么写: 46 | 47 | ``` 48 | 49 | CGPoint point = {.x = 0, .y= 0}; 50 | CGSize size = {.width = 10, .height = 10}; 51 | CGRect rect = {point, size}; 52 | CGRect rect2 = {.origin.x = 0, .origin.y = 0, .size.width = 10, .size.height = 10}; 53 | CGRect rect3 = {{.x = 0, .y = 0}, {.width = 10, .height = 10}}; 54 | 55 | ``` 56 | 57 | 这种写法更直观,但是没有代码补全. 两种写法的汇编代码是不一样的: 58 | 59 | 60 | 0.测试类 ClassFoo.m 61 | --- 62 | 63 | ``` 64 | // ClassFoo.m 65 | 66 | - (void)testMethod2 67 | { 68 | CGRect rect2 = {.origin.x = 0, .origin.y = 0, .size.width = 10, .size.height = 10}; 69 | } 70 | 71 | - (void)testMethod3 72 | { 73 | CGRect rect4 = CGRectMake(0, 0, 10, 10); 74 | } 75 | 76 | ``` 77 | 78 | 79 | 80 | 1. CGRectMake 的汇编代码( shell# clang -S ClassFoo.m -o ClassFoo.s): 81 | --- 82 | 83 | 84 | *.cfi_XX 为[CFI directives](https://sourceware.org/binutils/docs/as/CFI-directives.html).* 85 | 86 | 87 | 88 | ``` 89 | 90 | _CGRectMake: ## @CGRectMake 91 | .cfi_startproc 92 | ## BB#0: 93 | pushq %rbp 94 | Ltmp6: 95 | .cfi_def_cfa_offset 16 96 | Ltmp7: 97 | .cfi_offset %rbp, -16 98 | movq %rsp, %rbp 99 | Ltmp8: 100 | .cfi_def_cfa_register %rbp 101 | movq %rdi, %rax 102 | movsd %xmm0, -8(%rbp) 103 | movsd %xmm1, -16(%rbp) 104 | movsd %xmm2, -24(%rbp) 105 | movsd %xmm3, -32(%rbp) 106 | movsd -8(%rbp), %xmm0 107 | movsd %xmm0, -64(%rbp) 108 | movsd -16(%rbp), %xmm0 109 | movsd %xmm0, -56(%rbp) 110 | movsd -24(%rbp), %xmm0 111 | movsd %xmm0, -48(%rbp) 112 | movsd -32(%rbp), %xmm0 113 | movsd %xmm0, -40(%rbp) 114 | movq -64(%rbp), %rcx 115 | movq %rcx, (%rdi) 116 | movq -56(%rbp), %rcx 117 | movq %rcx, 8(%rdi) 118 | movq -48(%rbp), %rcx 119 | movq %rcx, 16(%rdi) 120 | movq -40(%rbp), %rcx 121 | movq %rcx, 24(%rdi) 122 | popq %rbp 123 | retq 124 | .cfi_endproc 125 | 126 | ``` 127 | 128 | 2. testMethod3(使用CGRectMake) 的汇编代码: 129 | --- 130 | 131 | ``` 132 | "-[classFoo testMethod3]": ## @"\01-[classFoo testMethod3]" 133 | .cfi_startproc 134 | ## BB#0: 135 | pushq %rbp 136 | Ltmp12: 137 | .cfi_def_cfa_offset 16 138 | Ltmp13: 139 | .cfi_offset %rbp, -16 140 | movq %rsp, %rbp 141 | Ltmp14: 142 | .cfi_def_cfa_register %rbp 143 | subq $64, %rsp 144 | leaq -48(%rbp), %rax 145 | xorps %xmm0, %xmm0 146 | movsd LCPI4_0(%rip), %xmm1 147 | movq %rdi, -8(%rbp) 148 | movq %rsi, -16(%rbp) 149 | movq %rax, %rdi 150 | movsd %xmm0, -56(%rbp) ## 8-byte Spill 151 | movsd -56(%rbp), %xmm2 ## 8-byte Reload 152 | movsd %xmm1, -64(%rbp) ## 8-byte Spill 153 | movaps %xmm2, %xmm1 154 | movsd -64(%rbp), %xmm2 ## 8-byte Reload 155 | movsd -64(%rbp), %xmm3 ## 8-byte Reload 156 | callq _CGRectMake // 在这里调用_CGRectMake 157 | addq $64, %rsp 158 | popq %rbp 159 | retq 160 | .cfi_endproc 161 | ``` 162 | 163 | 3. `CGRect rect2 = {.origin.x = 0, .origin.y = 0, .size.width = 10, .size.height = 10};` 的汇编代码: 164 | --- 165 | 166 | ``` 167 | "-[classFoo testMethod2]": ## @"\01-[classFoo testMethod2]" 168 | .cfi_startproc 169 | ## BB#0: 170 | pushq %rbp 171 | Ltmp9: 172 | .cfi_def_cfa_offset 16 173 | Ltmp10: 174 | .cfi_offset %rbp, -16 175 | movq %rsp, %rbp 176 | Ltmp11: 177 | .cfi_def_cfa_register %rbp 178 | movq %rdi, -8(%rbp) 179 | movq %rsi, -16(%rbp) 180 | movq "-[classFoo testMethod2].rect2"(%rip), %rsi 181 | movq %rsi, -48(%rbp) 182 | movq "-[classFoo testMethod2].rect2"+8(%rip), %rsi 183 | movq %rsi, -40(%rbp) 184 | movq "-[classFoo testMethod2].rect2"+16(%rip), %rsi 185 | movq %rsi, -32(%rbp) 186 | movq "-[classFoo testMethod2].rect2"+24(%rip), %rsi 187 | movq %rsi, -24(%rbp) 188 | popq %rbp 189 | retq 190 | .cfi_endproc 191 | 192 | ``` 193 | 194 | 195 | ####可以看到直接使用`{.origin.x = 0, .origin.y = 0, .size.width = 10, .size.height = 10}`虽然代码写起来会更繁琐,但是机器处理起来会更直接. 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /Articles/Class-Cluster-NSDictionary.md: -------------------------------------------------------------------------------- 1 | ##类簇子类化问题 2 | 3 | @References: 4 | 5 | @iBcker 一个能跑去给服务器找bug的风一样的少年 6 | 7 | @jiangrui 专业翻墙20年 8 | 9 | @zaishi 叫大仙 不解释 10 | 11 | 12 | 13 | ####名词定义: 14 | 1. 类 : 本文中`类`泛指isa指针所指Class 15 | 2. 类对象: 一个Class object,因为OC中类本身也是有isa指针,也是一个对象. 16 | 17 | 18 | ####问题: 19 | iOS的`Foundation`中有很多类簇,如`NSDictionary`、`NSString`、`NSArray`、`NSNumber`.假设现在子类化一个`NSDictionary`: 20 | 21 | @interface CustomDictionary : NSDictionary 22 | 23 | @end 24 | 25 | @implementation CustomDictionary 26 | 27 | @end 28 | 29 | 30 | 在子类`CustomDictionary`中什么都不做,先抛开Apple文档说明的子类化一个NSDictionary时必须实现的那几个方法不看,假装不知道,完全按照面向对象的一般思想想问题,然后做如下试验: 31 | 32 | 33 | 34 | int main(int argc, char * argv[]) { 35 | @autoreleasepool { 36 | NSDictionary *dict = [[NSDictionary alloc] 37 | initWithObjectsAndKeys:@"object1",@"key1", nil]; 38 | //断点1 39 | CustomDictionary *cDic = [[CustomDictionary alloc] 40 | initWithObjectsAndKeys:@"object1",@"key1", nil]; //line 1 41 | 42 | return UIApplicationMain(argc, argv, nil, 43 | NSStringFromClass([AppDelegate class])); 44 | } 45 | } 46 | 47 | 48 | 49 | 按照一般的OOP的思想,由于 在子类中并未对父类做任何修改,那么在 `line1`调用 `alloc`和`initWithObjectsAndKeys:`这两个方法,`cDic`应该与父类`NSDictionary`的实例化得到的对象拥有完全一样的方法或者说能力,那么应该是没有问题的。于是, 运行,看一下结果,注意在`line1`前设置了一个断点: 50 | 51 | 52 | 53 | (lldb) po [dict allKeys] 54 | <__NSArrayI 0x7fb7e340f4c0>( 55 | key1 56 | ) 57 | 58 | 59 | 60 | 运行至`断点1`处显然不会有任何问题,然后 打印出来`[dict allKeys]`的结果,可以看到是一个`__NSArrayI`对象,里面为`key1`,这是一个符合预期的结果.(这个`__NSArrayI`的意思是一个不可变的(immutable)数组对象,暂不作进一步讨论这个对象的类是什么类,且把他看作一个`NSArray`类实例化得到的一个对象.). 61 | 62 | 接下来,运行`line1`,程序Crash,错误信息如下: 63 | 64 | 65 | *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** 66 | -[NSDictionary initWithObjects:forKeys:count:]: method only defined for abstract class. 67 | Define -[CustomDictionary initWithObjects:forKeys:count:]!' 68 | 69 | 70 | 71 | 这里可以看出,当 调用`initWithObjectsAndKeys:`时,需要调用`initWithObjects:forKeys:count:`**这个Designated Initializer**,好理解.但是虽然 是没有在`CustomDictionary`中定义这个方法,但是按 之前的期望,第一步`[CustomDictionary alloc]` 这里应该调用的是`NSDictionary`的`alloc`,然后返回一个对象后再次调用`NSDictionary`的`initWithObjectsAndKeys:`方法,看起来和直接使用 `[[NSDictionary alloc] initWithObjectsAndKeys]` 没什么区别啊,为什么这里就说没有`initWithObjects:forKeys:count:`这方法了呢?为什么`[[NSDictionary alloc] initWithObjectsAndKeys]`调用时没有问题,而用 自己的 `CustomDictionary`类调用就出了问题呢? 72 | 73 | 74 | 75 | ####分析 76 | 这就是类簇的子类化的奥妙所在了. 做如下分析: 77 | 首先, 把`[[NSDictionary alloc] initWithObjectsAndKeys:@"object1",@"key1", nil];`拆开: 78 | 79 | 80 | id someObject = [NSDictionary alloc]; 81 | dict = [someObject init]; 82 | 83 | 84 | 85 | 然后 打印 `someObject`的类对象: 86 | 87 | 88 | (lldb) po [someObject class] 89 | __NSPlaceholderDictionary 90 | 91 | 可以看到这里alloc返回的是一个`__NSPlaceholderDictionary`类对象. 92 | 93 | 同样的 对`[[CustomDictionary alloc] initWithObjectsAndKeys:@"object1",@"key1", nil];`拆开: 94 | 95 | 96 | id someObjectC = [NSDictionary alloc]; 97 | cDic = [someObjectC init]; 98 | 99 | 100 | 101 | 然后 打印 `someObjectC`的类对象: 102 | 103 | (lldb) po [someObjectC class] 104 | CustomDictionary 105 | 106 | 107 | 可以看到这里alloc返回的是一个`CustomDictionary`类对象.按照 之前的分析,由于这里仍然调用的是`NSDictionary`的`alloc`方法,那么返回的`someObjectC`的class应该仍然是` __NSPlaceholderDictionary`才对,但是把这个打印出来,返回的居然是:`CustomDictionary`, 自己的类的指针。 108 | 109 | 其底层的原理就是:NSDictionary alloc时有个中间层,就是 上面看到的 __NSPlaceholderDictionary. 110 | alloc的对象先统一为这个类对象之后,在后面调用 __NSPlaceholderDictionary的类方法时,比如initWithObjectsAndKeys 才返回具体的类,即在__NSPlaceholderDictionary这一层做个“代理工厂”,根据调用的不同init方法再返回具体的类。 111 | 112 | 开始对`alloc`这个方法产生的兴趣,这个方法在NSObject中实现,NSDicionary继承自NSObject,NSObject中`alloc`实现为: 113 | 114 | 115 | + (id) alloc 116 | { 117 | return [self allocWithZone: NSDefaultMallocZone()]; 118 | } 119 | 120 | 121 | 122 | 当执行`[NSDictionary alloc]`时,由runtime的消息转发机制会转到NSDictionary父类NSObject的alloc中执行,其中`self`是当前消息的receiver,在 现在的情况下就是NSDictionary类对象。于是 转而关心`NSDictionary`中对`allocWithZone`的实现了. 123 | 124 | GNUStep上对NSDictionary的`allocWithZone:`实现: 125 | 126 | 127 | 128 | + (id) allocWithZone: (NSZone*)z 129 | { 130 | if (self == [NSDictionary Class]) 131 | { 132 | return NSAllocateObject(NSPlaceholderDictionary, 0, z); 133 | } 134 | else 135 | { 136 | return NSAllocateObject(self, 0, z); 137 | } 138 | } 139 | 140 | 141 | 142 | 143 | ####结果 1 144 | 可以发现,当只用`NSDictionary`调用`alloc`的时候,由于`self == [NSDictionary class]`,所以这时返回的是`NSPlaceholderDictionary`的类对象;而使用其他类(比如派生类)调用`alloc`时,返回的是`super`的 `alloc`,这里也就是`[NSObject alloc]`,而`NSObject`的`alloc`方法返回的是调用类的类对象,所以在用自己的`CustomDictionary`类调用时,返回的就是`CustomDictionary`类的类对象了。 145 | 146 | 那为什么明明`NSDictionary`中明明定义了`initWithObjects:forKeys:count`方法,但是必须要一个定义了(覆盖)`initWithObjects:forKeys:count`的子类返回时才能正常运行呢?来看一下`NSDictionary`中对`initWithObjects:forKeys:count`的实现: 147 | 148 | 149 | 150 | 151 | - (id) initWithObjects: (const id[])objects 152 | forKeys: (const id [])keys 153 | count: (NSUInteger)count 154 | { 155 | return [self subclassResponsibility: _cmd]; 156 | } 157 | 158 | - (id) subclassResponsibility: (SEL)aSel 159 | { 160 | char c = (class_isMetaClass(object_getClass(self)) ? '+' : '-'); 161 | 162 | [NSException raise: NSInvalidArgumentException 163 | format: @"[%@%c%@] should be overridden by subclass", 164 | NSStringFromClass([self class]), c, 165 | aSel ? (id)NSStringFromSelector(aSel) : (id)@"(null)"]; 166 | return self; // Not reached 167 | } 168 | 169 | 170 | 171 | 可以看到,在`NSDictionary`中对`initWithObjects:forKeys:count:`的实现,就是抛出一个异常,若直接调用`NSDictionary`的该方法就会Crash,所以必须是一个覆盖了该方法的子类才能调用`initWithObjects:forKeys:count:`方法.这就是为什么当使用`__NSPlaceholderDictionary`时不会Crash(__NSPlaceholderDictionary中覆盖了该方法),而当使用自己写的没有覆盖该方法的子类`CustomDictionary`时就会Crash的原因. 172 | 173 | 174 | ####继续分析: 175 | 176 | Apple的文档中对子类化NSDictionry时候要求实现的四个方法: 177 | 178 | 179 | Methods to Override 180 | If you do need to subclass NSDictionary, take into account that it is a class cluster. 181 | Any subclass must override the following primitive methods: 182 | 183 | initWithObjects:forKeys:count: 184 | 185 | @property count 186 | 187 | objectForKey: 188 | 189 | keyEnumerator: 190 | 191 | The other methods of NSDictionary operate by invoking one or more of these primitives. 192 | The non-primitive methods provide convenient ways of accessing multiple entries at once. 193 | 194 | 195 | 而在NSDictionary中对其他三个方法的实现完全类似: 196 | 197 | 198 | - (NSEnumerator*) keyEnumerator 199 | { 200 | return [self subclassResponsibility: _cmd]; 201 | } 202 | 203 | - (id) objectForKey: (id)aKey 204 | { 205 | return [self subclassResponsibility: _cmd]; 206 | } 207 | 208 | - (NSUInteger) count 209 | { 210 | [self subclassResponsibility: _cmd]; 211 | return 0; 212 | } 213 | 214 | 215 | 216 | 217 | 218 | 其实在调用`[NSDictionary alloc]`时候返回的`__NSPlaceholderDictionary`类对象就是`NSDictionary`类对象的一个子类: 219 | 220 | 221 | (lldb) po [__NSPlaceholderDictionary isSubclassOfClass:[NSDictionary class]] 222 | 223 | true 224 | 225 | 226 | 227 | `[[NSDictionary alloc] init]`返回的也是一个 `__NSDicionaryI`类的对象,也是NSDictionary的一个子类 228 | 229 | 230 | (lldb) po [__NSDictionaryI isSubclassOfClass:[NSDictionary class]] 231 | 232 | true 233 | 234 | 235 | 236 | 如果 在子类化时不实现上面文档中四个方法,就会在使用特定的方法的Crash,如前面所做的那样不覆盖`initWithObjects:forKeys:count:`方法的话, 在`initWithObjectsAndKeys:`时就会Crash; 如果 不实现`@property count`, 当调用 `allKeys`时就会在该方法抛出异常(当然,直接调用count也会Crash). 237 | 238 | 239 | ####总之 240 | 241 | 242 | 在子类化一个NSDictionary时,不对父类做任何修改的前提下并没有具备父类完全一样的方法的原因NSDictionary在alloc和init时返回的实际上是NSDicationary的子类,覆盖了NSDictionary中一些特定的方法(primitives methods)。 243 | 244 | 245 | ~~**Apple文档中对子类化NSDictionary有较详细的说明,并给出了两种不同形式的实现方式.但个人偏见认为,子类化类簇应该是个Bad idea** 246 | ~~ 247 | 248 | Foundation中的实现是在alloc时判断调用者的类型,并在primitives methods中抛出异常. 当然,这么做的原因还是保持类簇或者说抽象工厂模式的初衷:隐藏实现细节. 249 | 250 | 251 | ####扩展 252 | 253 | 理解了NSDictionary这个类簇的实现和子类化时的问题,可以引申到NSString(已验证)、NSArray(未验证)、NSNumber(未验证)这些类簇的实现和子类化,本质上都是一样的。 254 | 255 | ####补充 256 | 根据[@iBcker](http://ibcker.me)分享,其使用Xcode自带的添加symbol breakpoint的方式来追踪了类簇实例化一个对象时所调用的方法,得到的结论与以上通过分析Core Foundation源码得到的结论一致. 257 | 258 | 其分析过程通过添加 objc_msgSend 符号断点,并在断点处的添加两个action: 259 | 260 | 1.po object_getClass($rdi) //打印调用者所属类 261 | 262 | 2.x/s $rsi //打印调用的方法名 263 | 264 | 265 | 可以看到类簇在实例化一个对象时底层真正调用了哪些方法、以及分别是谁调用的. 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | -------------------------------------------------------------------------------- /Articles/Danger of Method Swizzling.md: -------------------------------------------------------------------------------- 1 | Date: 2015-05-12 2 | Title: Danger of Method Swizzling 3 | Published: true 4 | Type: post 5 | 6 | ## Danger of Method Swizzling 7 | 8 | 9 | Using method sizzling is like using sharp knives in the kitchen. Some people are scared of sharp knives because they think they'll cut themselves badly, but the truth is that sharp knives are safer. 10 | 11 | Method swizzling can be used to write better, more efficient, more maintainable code. It can also be abused and lead to horrible bugs. 12 | 13 | ###Background 14 | 15 | As with all design patters, if we are fully aware of the consequences of the pattern, we are able to make more informed decisions about whether or not to use it. Singletons are a good example of something that's pretty controversial, and for good reason — they're really hard to implement properly. Many people still choose to use singletons, though. The same can be said about swizzling. You should form your own opinion once you fully understand both the good and the bad. 16 | 17 | ###Discussion 18 | 19 | Here are some of the pitfalls of method swizzling: 20 | 21 | Method swizzling is not atomic 22 | Changes behavior of un-owned code 23 | Possible naming conflicts 24 | Swizzling changes the method's arguments 25 | The order of swizzles matters 26 | Difficult to understand (looks recursive) 27 | Difficult to debug 28 | These points are all valid, and in addressing them we can improve both our understanding of method swizzling as well as the methodology used to achieve the result. I'll take each one at a time. 29 | 30 | ###Method swizzling is not atomic 31 | 32 | I have yet to see an implementation of method swizzling that is safe to use concurrently1. This is actually not a problem in 95% of cases that you'd want to use method swizzling. Usually, you simply want to replace the implementation of a method, and you want that implementation to be used for the entire lifetime of your program. This means that you should do your method swizzling in +(void)load. The load class method is executed serially at the start of your application. You won't have any issues with concurrency if you do your swizzling here. If you were to swizzle in +(void)initialize, however, you could end up with a race condition in your swizzling implementation and the runtime could end up in a weird state. 33 | 34 | ###Changes behavior of un-owned code 35 | 36 | This is an issue with swizzling, but it's kind of the whole point. The goal is to be able to change that code. The reason that people point this out as being a big deal is because you're not just changing things for the one instance of NSButton that you want to change things for, but instead for all NSButton instances in your application. For this reason, you should be cautious when you swizzle, but you don't nee to avoid it altogether. 37 | 38 | Think of it this way... if you override a method in a class and you don't call the super class method, you may cause problems to arise. In most cases, the super class is expecting that method to be called (unless documented otherwise). If you apply this same thought to swizzling, you've covered most issues. Always call the original implementation. If you don't, you're probably changing too much to be safe. 39 | 40 | ###Possible naming conflicts 41 | 42 | Naming conflicts are an issue all throughout Cocoa. We frequently prefix class names and method names in categories. Unfortunately, naming conflicts are a plague in our language. In the case of swizzling, though, they don't have to be. We just need to change the way that we think about method swizzling slightly. Most swizzling is done like this: 43 | 44 | ``` 45 | @interface NSView : NSObject 46 | - (void)setFrame:(NSRect)frame; 47 | @end 48 | 49 | @implementation NSView (MyViewAdditions) 50 | 51 | - (void)my_setFrame:(NSRect)frame { 52 | // do custom work 53 | [self my_setFrame:frame]; 54 | } 55 | 56 | + (void)load { 57 | [self swizzle:@selector(setFrame:) with:@selector(my_setFrame:)]; 58 | } 59 | 60 | @end 61 | ``` 62 | This works just fine, but what would happen if my_setFrame: was defined somewhere else? This problem isn't unique to swizzling, but we can work around it anyway. The workaround has an added benefit of addressing other pitfalls as well. Here's what we do instead: 63 | 64 | ``` 65 | @implementation NSView (MyViewAdditions) 66 | 67 | static void MySetFrame(id self, SEL _cmd, NSRect frame); 68 | static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame); 69 | 70 | static void MySetFrame(id self, SEL _cmd, NSRect frame) { 71 | // do custom work 72 | SetFrameIMP(self, _cmd, frame); 73 | } 74 | 75 | + (void)load { 76 | [self swizzle:@selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP]; 77 | } 78 | 79 | @end 80 | 81 | ``` 82 | While this looks a little less like Objective-C (since it's using function pointers), it avoids any naming conflicts. In principle, it's doing the exact same thing as standard swizzling. This may be a bit of a change for people who have been using swizzling as it has been defined for a while, but in the end, I think that it's better. The swizzling method is defined thusly: 83 | 84 | ``` 85 | typedef IMP *IMPPointer; 86 | 87 | BOOL class_swizzleMethodAndStore(Class class, SEL original, IMP replacement, IMPPointer store) { 88 | IMP imp = NULL; 89 | Method method = class_getInstanceMethod(class, original); 90 | if (method) { 91 | const char *type = method_getTypeEncoding(method); 92 | imp = class_replaceMethod(class, original, replacement, type); 93 | if (!imp) { 94 | imp = method_getImplementation(method); 95 | } 96 | } 97 | if (imp && store) { *store = imp; } 98 | return (imp != NULL); 99 | } 100 | 101 | @implementation NSObject (FRRuntimeAdditions) 102 | + (BOOL)swizzle:(SEL)original with:(IMP)replacement store:(IMPPointer)store { 103 | return class_swizzleMethodAndStore(self, original, replacement, store); 104 | } 105 | @end 106 | 107 | ``` 108 | 109 | ###Swizzling changes the method's arguments 110 | 111 | This is the big one in my mind. This is the reason that standard method swizzling should not be done. You are changing the arguments passed to the original method's implementation. This is where it happens: 112 | 113 | ``` 114 | [self my_setFrame:frame]; 115 | ``` 116 | 117 | What line does is: 118 | 119 | objc_msgSend(self, @selector(my_setFrame:), frame); 120 | Which will use the runtime to look up the implementation of my_setFrame:. Once the implementation is found, it invokes the implementation with the same arguments that were given. The implementation it finds is the original implementation of setFrame:, so it goes ahead and calls that, but the _cmd argument isn't setFrame: like it should be. It's now my_setFrame:. The original implementation is being called with an argument it never expected it would receive. This is no good. 121 | 122 | There's a simple solution — use the alternative swizzling technique defined above. The arguments will remain unchanged! 123 | 124 | ###The order of swizzles matters 125 | 126 | The order in which methods get swizzled matters. Assuming setFrame: is only defined on NSView, imagine this order of things: 127 | 128 | ``` 129 | [NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)]; 130 | [NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)]; 131 | [NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)]; 132 | ``` 133 | What happens when the method on NSButton is swizzled? Well most swizzling will ensure that it's not replacing the implementation of setFrame: for all views, so it will pull up the instance method. This will use the existing implementation to re-define setFrame: in the NSButton class so that exchanging implementations doesn't affect all views. The existing implementation is the one defined on NSView. The same thing will happen when swizzling on NSControl (again using the NSView implementation). 134 | 135 | When you call setFrame: on a button, it will therefore call your swizzled method, and then jump straight to the setFrame: method originally defined on NSView. The NSControl and NSView swizzled implementations will not be called. 136 | 137 | But what if the order were: 138 | 139 | ``` 140 | [NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)]; 141 | [NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)]; 142 | [NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)]; 143 | ``` 144 | 145 | Since the view swizzling takes place first, the control swizzling will be able to pull up the right method. Likewise, since the control swizzling was before the button swizzling, the button will pull up the control's swizzled implementation of setFrame:. This is a bit confusing, but this is the correct order. How can we ensure this order of things? 146 | 147 | Again, just use load to swizzle things. If you swizzle in load and you only make changes to the class being loaded, you'll be safe. The load method guarantees that the super class load method will be called before any subclasses. We'll get the exact right order! 148 | 149 | ###Difficult to understand (looks recursive) 150 | 151 | Looking at a traditionally defined swizzled method, I think it's really hard to tell what's going on. But looking at the alternative way we've done swizzling above, it's pretty easy to understand. This one's already been solved! 152 | 153 | ###Difficult to debug 154 | 155 | One of the confusions during debugging is seeing a strange backtrace where the swizzled names are mixed up and everything gets jumbled in your head. Again, the alternative implementation addresses this. You'll see clearly named functions in backtraces. Still, swizzling can be difficult to debug because it's hard to remember what impact the swizzling is having. Document your code well (even if you think you're the only one who will ever see it). Follow good practices, and you'll be alright. It's not harder to debug than multi-threaded code. 156 | 157 | ###Conclusion 158 | 159 | Method swizzling is safe if used properly. A simple safety measure you can take is to only swizzle in load. Like many things in programming, it can be dangerous, but understanding the consequences will allow you use it properly. 160 | 161 | ### 162 | Using the above defined swizzling method, you could make things thread safe if you were to use trampolines. You would need two trampolines. At the start of the method, you would have to assign the function pointer, store, to a function that spun until the address to which store pointed to changed. This would avoid any race condition in which the swizzled method was called before you were able to set the store function pointer. You would then need to use a trampoline in the case where the implementation isn't already defined in the class and have the trampoline lookup and call the super class method properly. Defining the method so it dynamically looks up the super implementation will ensure that the order of swizzling calls does not matter. -------------------------------------------------------------------------------- /Articles/Dealloc.md: -------------------------------------------------------------------------------- 1 | ### Dealloc 在哪个线程执行 2 | --- 3 | 4 | ###1. 如果是一道选择题,那么有可能的选择是: 5 | 6 | > A. 所有对象的dealloc方法会在主线程调用 7 | > B. 一个对象的dealloc方法会在分配该对象的线程被调用 8 | > C. 一个对象的dealloc方法会在该对象的引用计数变为0的线程被调用 9 | 10 | 一小段代码便可以试出答案(thx to [@CarinaT](https://github.com/CarinaTT)): 11 | 12 | ``` 13 | 14 | #import "ViewController.h" 15 | 16 | @interface ClassFoo : NSObject 17 | @end 18 | 19 | @implementation ClassFoo 20 | 21 | - (void)dealloc 22 | { 23 | NSLog(@"dealloc is excuted in thread : %@, object : %@", [NSThread currentThread], self); 24 | } 25 | 26 | @end 27 | 28 | 29 | 30 | @interface ViewController () 31 | @property (nonatomic, strong) NSMutableArray *array; 32 | @end 33 | 34 | @implementation ViewController 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | // Do any additional setup after loading the view, typically from a nib. 39 | 40 | _array = [NSMutableArray array]; 41 | ClassFoo *objectFoo = [[ClassFoo alloc] init]; 42 | NSLog(@"Thread: %@, object : %@", [NSThread currentThread],objectFoo); 43 | [_array addObject:objectFoo]; 44 | 45 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 46 | [[NSThread currentThread] setName:@"DISPATCH_QUEUE_Thread_Custom"]; 47 | [_array removeAllObjects]; 48 | }); 49 | 50 | // dispatch_async(dispatch_get_main_queue(), ^{ 51 | // [_array removeAllObjects]; 52 | // }); 53 | 54 | 55 | 56 | } 57 | 58 | 59 | @end 60 | 61 | 62 | 63 | ``` 64 | 65 | 66 | 67 | 68 | 69 | 运行得到的输出为: 70 | 71 | ``` 72 | 2015-06-24 14:27:15.261 DeallocDemo[53565:38948231] Thread: {number = 1, name = main}, object : 73 | 2015-06-24 14:27:15.262 DeallocDemo[53565:38948390] dealloc is excuted in thread : {number = 2, name = DISPATCH_QUEUE_Thread_Custom}, object : 74 | 75 | ``` 76 | 77 | 可见, `objectFoo` 的分配是在主线程, 然后用一个数组来强引用到该对象, 并在一个`dispatch_queue`里清空数组,以达到释放 `objectFoo`的目的,输出的结果表明答案应该选 `C: 一个对象的dealloc方法会在该对象的引用计数变为0的线程被调用 `. 78 | 79 | 80 | 81 | ###2. 在 [@Matt Galloway](https://twitter.com/mattjgalloway) 的《Effective Objective-C 2.0》中(page164)对这个问题有描述: 82 | 83 | *Also, the dealloc method is called on the thread in which the final release that caused the retain count to zero occurred.* 84 | 85 | 86 | 87 | [^1]:感谢[@CarinaT](https://github.com/CarinaTT). 88 | -------------------------------------------------------------------------------- /Articles/Install-PhonyDebugger.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![PonyDebugger Logo](https://github.com/square/PonyDebugger/raw/master/Documentation/Images/Logo.png) 4 | 5 | PhonyDebugger的正确安装姿势 6 | -------- 7 | > ps. 今天玩了一下PhonyDebugger,虽然我们在开发中UI的调试有Reveal,网络访问抓包有Charles,但多了解一个Debug工具也无碍. 功能一般,可能习惯了Reveal和Charles,觉得PD只适合玩玩,用起来还是不如前面两个好用. 8 | 9 | PD提供的功能是在*浏览器中*: 10 | 11 | * 实时查看或修改UI元素 12 | * 实时查看网络访问,支持HTTPS 13 | * 实时查看Core Data数据 14 | * Remote Logging 15 | 16 | 具体的Feature可以查看PD的[github](https://github.com/square/PonyDebugger)页.   17 | 18 | 19 | 20 | 1. Server端安装 21 | --- 22 | 23 | ###安装 24 | 中间有些访问是被墙了的,如第一步会需要下载http://storage.googleapis.com/chromium-browser-continuous/Mac/152100/devtools_frontend.zip.所以翻墙再下.[shadowsocks](https://github.com/shadowsocks/shadowsocks) + [proxychains4](https://github.com/rofl0r/proxychains-ng) 来翻墙是个不错的选择. 25 | 26 | 27 | shell下: 28 | 29 | ``` 30 | proxychains4 curl -s https://cloud.github.com/downloads/square/PonyDebugger/bootstrap-ponyd.py | python - --ponyd-symlink=/usr/local/bin/ponyd ~/Library/PonyDebugger 31 | ``` 32 | 33 | 34 | ``` 35 | source ~/Library/PonyDebugger/bin/activate 36 | ``` 37 | 38 | ``` 39 | proxychains4 pip install -U -e git+https://github.com/square/PonyDebugger.git#egg=ponydebugger --allow-external pybonjour --allow-unverified pybonjour 40 | ``` 41 | 42 | ``` 43 | proxychains4 ponyd update-devtools 44 | ``` 45 | 46 | ###启动 47 | 48 | 49 | shell 下: 50 | 51 | ``` 52 | ponyd serve --listen-interface=127.0.0.1 53 | ``` 54 | 55 | 然后 56 | ``` 57 | 启动浏览器,访问http://localhost:9000 58 | ``` 59 | 60 | 一切正确将看到如下页面: 61 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/localhost.png) 62 | 63 | 64 | 2. iOS客户端安装 65 | --- 66 | 这里没什么好说的,官方README说的比较清楚了,可以直接安装成功.建议使用CocoaPods安装,简单快捷还便于管理.搬运一下: 67 | 68 | #### CocoaPods 69 | 70 | [CocoaPods](http://cocoapods.org/) automates 3rd party dependencies in 71 | Objective-C. 72 | 73 | Install the ruby gem. 74 | 75 | $ sudo gem install cocoapods 76 | $ pod setup 77 | 78 | > Depending on your Ruby installation, you may not have to run as sudo to 79 | > install the cocoapods gem. 80 | 81 | Create a Podfile. You must be running on iOS 5 or above. 82 | 83 | platform :ios, '5.0' 84 | pod 'PonyDebugger', '~> 0.4.3' 85 | 86 | If you would like to use the latest version of PonyDebugger, point to the Github 87 | repository directly. 88 | 89 | pod 'PonyDebugger', :git => 'https://github.com/square/PonyDebugger.git' 90 | 91 | Install dependencies. 92 | 93 | $ pod install 94 | 95 | When using CocoaPods, you must open the `.xcworkspace` file instead of the 96 | project file when building your project. 97 | 98 | 99 | 3. iOS客户端工程中启动PDDebugger : 100 | --- 101 | 102 | Example: 103 | 104 | ``` 105 | 106 | // AppDelegate.m 107 | 108 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 109 | { 110 | 111 | #if DEBUG 112 | [self enablePonyDebugger]; 113 | #endif 114 | ... 115 | return YES; 116 | } 117 | 118 | 119 | 120 | #pragma mark - PonyDebugger 121 | 122 | - (void)enablePonyDebugger 123 | { 124 | #if DEBUG 125 | 126 | [MobClick setCrashReportEnabled:NO]; 127 | 128 | PDDebugger *debugger = [PDDebugger defaultInstance]; 129 | 130 | // Enable Network debugging, and automatically track network traffic that comes through any classes that implement either NSURLConnectionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate or NSURLSessionDataDelegate methods. 131 | [debugger enableNetworkTrafficDebugging]; 132 | [debugger forwardAllNetworkTraffic]; 133 | 134 | // Enable View Hierarchy debugging. This will swizzle UIView methods to monitor changes in the hierarchy 135 | // Choose a few UIView key paths to display as attributes of the dom nodes 136 | [debugger enableViewHierarchyDebugging]; 137 | [debugger setDisplayedViewAttributeKeyPaths:@[@"frame", @"hidden", @"alpha", @"opaque", @"accessibilityLabel", @"text"]]; 138 | 139 | // Connect to a specific host 140 | [debugger connectToURL:[NSURL URLWithString:@"ws://localhost:9000/device"]]; 141 | // Or auto connect via bonjour discovery 142 | //[debugger autoConnect]; 143 | // Or to a specific ponyd bonjour service 144 | //[debugger autoConnectToBonjourServiceNamed:@"MY PONY"]; 145 | 146 | // Enable remote logging to the DevTools Console via PDLog()/PDLogObjects(). 147 | [debugger enableRemoteLogging]; 148 | 149 | #endif/*if DEBUG*/ 150 | 151 | } 152 | 153 | 154 | ``` 155 | 156 | 4. 运行App,然后刷新浏览器,一切正常将看到自己的App在浏览器中显示,如下图: 157 | --- 158 | 159 | 160 | 点击App进去就可以开始使用PD了. 161 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/connected.jpg) 162 | 163 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/inside.jpg) 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /Articles/Little-code-block.md: -------------------------------------------------------------------------------- 1 | ### 不需要复用的代码块的写法 2 | --- 3 | 4 | 5 | 6 | ####1. 这种写法比较整洁,便于不需要复用的代码的分块. 7 | 8 | ``` 9 | // ViewController.m 10 | 11 | @interface ViewController () 12 | @property (weak, nonatomic) UIView *anyView; 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | #pragma clang diagnostic push 21 | #pragma clang diagnostic ignored "-Warc-unsafe-retained-assign" 22 | self.anyView = ({ 23 | UIView *view = [[UIView alloc] initWithFrame:(CGRect){{.x = 0, .y= 0},{.width = 10, .height = 20}}]; 24 | [self.view addSubview:view]; 25 | /** 26 | * ... 一段长长的代码 27 | */ 28 | view; 29 | }); 30 | 31 | 32 | self.anotherView = ({ 33 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 34 | [button setTintColor:UIColor.blueColor]; 35 | [button setTitle:@"Title" forState:UIControlStateNormal]; 36 | [button setImage:[UIImage imageNamed:@"imageNameFoo"] forState:UIControlStateNormal]; 37 | /** 38 | * ... 一段长长的代码 39 | */ 40 | button; 41 | }); 42 | #pragma clang diagnostic pop 43 | } 44 | 45 | ``` 46 | 47 | 48 | ####2. 这种写法的来源: [GNU C](https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html) 49 | 50 | 51 | 摘自https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html : 52 | 53 | A compound statement enclosed in parentheses may appear as an expression in GNU C. This allows you to use loops, switches, and local variables within an expression. 54 | 55 | Recall that a compound statement is a sequence of statements surrounded by braces; in this construct, parentheses go around the braces. For example: 56 | ``` 57 | ({ int y = foo (); int z; 58 | if (y > 0) z = y; 59 | else z = - y; 60 | z; }) 61 | ``` 62 | is a valid (though slightly more complex than necessary) expression for the absolute value of foo (). 63 | 64 | 65 | 66 | 67 | 在GNU C 中, 这种写法用来定义Macro. 如果max()被定义为: 68 | 69 | ``` 70 | #define max(a,b) ((a) > (b) ? (a) : (b)) 71 | 72 | ``` 73 | 则需要两次计算a和b的值,会存在副作用,如: 74 | 75 | ``` 76 | int o1 = 1, o2 = 2; 77 | int c = max( o1+= 1 ,o2+=1); // 预期c = 3, 但实际 c = 4, 因为连续计算了两次操作数b 78 | 79 | ``` 80 | 81 | 如果知道两个操作数的类型,并配合使用({})这种写法,可以避免上述问题: 82 | 83 | ``` 84 | #define maxint(a,b) \ 85 | ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) 86 | 87 | ``` 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Articles/Touch-events-outside.md: -------------------------------------------------------------------------------- 1 | ###子View在父view的外部时的点击事件处理实例 2 | 3 | 4 | ###问题 5 | --- 6 | 有两种常见的需求会需要我们去修改hitTest事件: 7 | > 1. 扩大点击区域,即一个UIButton在屏幕上显示的大小较小,但是希望用户在点击这个UIButton周围的一定范围内时,该UIButton能响应点击事件. 8 | > 2. 子View在父View的外部,而子View仍然想接受点击事件. 9 | 10 | 11 | 12 | 13 | 14 | ###先说原理 15 | --- 16 | 17 | iOS中使用`hit-testing`来找到一个`touch`对应的view. 18 | 19 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/hit-testing.jpg) 20 | 21 | 22 | 23 | 24 | 25 | ### 方案 26 | --- 27 | 两种需求都可以归结为hitTest事件的修改. 28 | 29 | 1. 先给出扩大UIButton点击区域的方案. 30 | 31 | ``` 32 | // UIButton+ExtendHitTest.h 33 | 34 | #import 35 | 36 | @interface UIButton (ExtendHitTest) 37 | @property(nonatomic, assign) UIEdgeInsets hitTestEdgeInsets; 38 | @end 39 | 40 | 41 | 42 | 43 | // UIButton+ExtendHitTest.m 44 | 45 | #import "UIButton+ExtendHitTest.h" 46 | #import 47 | 48 | 49 | static NSString *const kHitTestEdgeInsetsKey; 50 | 51 | @implementation UIButton (ExtendHitTest) 52 | @dynamic hitTestEdgeInsets; 53 | 54 | 55 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 56 | if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) { 57 | return [super pointInside:point withEvent:event]; 58 | } 59 | 60 | CGRect relativeFrame = self.bounds; 61 | CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets); 62 | 63 | return CGRectContainsPoint(hitFrame, point); 64 | } 65 | 66 | 67 | #pragma mark - Setter 68 | -(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { 69 | NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)]; 70 | objc_setAssociatedObject(self, &kHitTestEdgeInsetsKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 71 | } 72 | 73 | #pragma mark - Getter 74 | -(UIEdgeInsets)hitTestEdgeInsets { 75 | NSValue *value = objc_getAssociatedObject(self, &kHitTestEdgeInsetsKey); 76 | if(value) { 77 | UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets; 78 | }else { 79 | return UIEdgeInsetsZero; 80 | } 81 | } 82 | @end 83 | 84 | ``` 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Articles/When-layoutsubviews-get-called.md: -------------------------------------------------------------------------------- 1 | === 2 | 3 | Date: 2015-05-12 4 | Title: 关于UIView中layoutSubviews何时被调用 5 | Published: true 6 | Type: post 7 | 8 | --- 9 | ##关于UIView中layoutSubviews何时被调用 10 | 11 | 12 | 13 | ####1 测试环境: 14 | 15 | 1. 模拟器iOS7,模拟器iOS8,所有的layoutSubviews方法都仅仅调用[super layoutSubviews], 即 16 | 17 | ``` 18 | - (void)layoutSubviews 19 | { 20 | [super layoutSubviews]; 21 | NSLog(@"%s",__func__); 22 | } 23 | 24 | ``` 25 | 26 | === 27 | ####2 视图关系: 28 | 29 | * View0 – UIView class, root view for examples(ViewController's primary view) 30 | * View1 – UIScrollView class, subview of View0 31 | * View1.1 – UIView class, subview of View1 (No autoresize mask) 32 | * View1.2 – UIView class, another subview of View1 (Autoresize mask – flexible width) 33 | 34 | 35 | === 36 | ####3 测试结果 37 | 38 | 0. initWithFrame*不会*调用layoutSubviews. [View0 addSubview:View1],View0和View1的layoutSubviews方法都会被调用,先View0的后View1的。 39 | 40 | 41 | 42 | 43 | 1. 当[View1 addSubview:View1.1]时, View1和View1.1的layoutSubviews方法都会被调用,先View1的后View1.1的。 44 | 45 | 46 | 47 | 2. 当[View1.1 removeFromSuperview]时, View1和View1.1的layoutSubviews方法都会被调用,先View1的后View1.1的。 48 | 49 | 50 | 51 | 3. View1.1的bounds变化时(*不是frame*),View1和View1.1的layoutSubviews都会被调用,先View1的后View1.1的。 52 | 53 | 54 | 55 | 56 | 4. 当View1的bounds发生变化时,调用View1和View1.2的layoutSubviews. 即:`若子view的autoresizeMask不为none时,父view的bounds变化会引起该子view的layoutSubviews被调用.` 57 | 58 | 59 | 60 | 5. 在View1已经add了View1.1后,再[View1 addSubview:View1.2],调用View1、View1.2的layoutSubviews,*并不会调用View1.1的layoutSubviews*. 61 | 62 | 63 | 6. 在layoutSubviews中改变子view的bounds(size),`不会引起循环的layoutSubviews调用.` 64 | 65 | 66 | 7. 滑动View1调用View1的layoutSubviews. 并不调用View0的layoutSubviews. 67 | 68 | === 69 | ####4 便于查看: 70 | 71 | * View0 – UIView class, root view for examples(ViewController's primary view) 72 | * View1 – UIScrollView class, subview of View0 73 | * View1.1 – UIView class, subview of View1 (No autoresize mask) 74 | * View1.2 – UIView class, another subview of View1 (Autoresize mask – flexible width) 75 | 76 | 77 | 78 | 79 | | Method | View0 | View1 | View1.1 | View1.2 | 80 | | ------------ | ------------- | ------------ |------------- | ------------ | 81 | | [[View1 alloc] initWithFrame] | ✕ |✕ |✕ | ✕ | 82 | | [View0 addSubview:View1] | ✓ | ✓ |✕ | ✕ | 83 | | [View1 removeFromSuperview]| ✓ | ✕ |✕ | ✕ | 84 | | [View1 addSubview:View1.2]| ✕ | ✓ |✕ | ✓ | 85 | | [View1.1 changeSize]| ✕ | ✓ |✓ | ✕ | 86 | | [View1.2 changeSize]| ✕ | ✓ |✕ | ✓ | 87 | | [View1 changeSize]| ✓ | ✕ |✕ | ✓ | 88 | | [View1 scroll]| ✕ | ✓ |✕ | ✕ | 89 | | change size of View1.1 in layoutSubviews of View1| ✕ | ✕ |✕ | ✕ | 90 | | Rotate device | ✓ | ✓ |✓ | ✓ | 91 | 92 | 93 | === 94 | 95 | 96 | -------------------------------------------------------------------------------- /Articles/common-debug-tips.md: -------------------------------------------------------------------------------- 1 | ##iOS 常用 lldb Xcode 调试技巧 2 | 3 | 4 | ### 1. lldb: po 5 | 6 | > print object 的缩写,最常用的命令,在lldb中打印一个对象. 7 | 8 | > 当该对象实现了 description方法时会打印description方法返回的NSString. 9 | 10 | 11 | > 联调Mach-O类型为`Relocatable Object File`的库时,直接打印可能会报错,将Mach-O换成`Static Library` . 12 | 13 | > 对于基础类型,使用`p`而不是`po`;如果是打印基础类型的返回值,前面加上类型转换,如`p (BOOL)[ObjectFoo methodFooThatReturnsABoolean]` 14 | 15 | 16 | > 附加打印时的格式:`print/`, 如: `print/x 16`时输出`0x10`,[常用格式符](https://sourceware.org/gdb/onlinedocs/gdb/Output-Formats.html): 17 | 18 | 19 | 20 | |格式控制符|类型| 21 | |---|---| 22 | |c|char *| 23 | |s|字符串| 24 | |x|16进制| 25 | |c|char *| 26 | |a|地址| 27 | 28 | 29 | ### 2. lldb: e 30 | > 执行一个表达式,如`e [ObjectFoo excuteMethodFoo]` 31 | 32 | 33 | 34 | ### 3. lldb: 控制程序执行逻辑 35 | 36 | |命令|操作| 37 | |---|---| 38 | |c|continue| 39 | |n|thread step-inst-over| 40 | |ni|thread step-inst-over| 41 | |thread return |char *| 42 | 43 | 其中`thread return [-x] -- [] `和`thread return []`在调试时非常有用,举例: 44 | 45 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/lldb-demo-1.png) 46 | 47 | 在上面断点时,lldb中输入`thread return NO`可以模拟一个返回值,其他对象类型的返回值也是同样的.如某个返回值需要复杂的操作才能获得,那么可以直接通过这种方式来mock一个返回. 48 | 49 | 50 | ### 4. lldb: bt / bt all 51 | 打印backtrace, 当程序crash或断在某处时,可以查看调用栈. 52 | > `bt`打印当前线程的调用栈. 53 | > 54 | > `bt all`打印所有线程的调用栈. 55 | 56 | ### 5. lldb: 打印exception 57 | > 在`objc_exception_throw`时,exception会压栈,可以$arg1寄存器来查看异常 58 | 59 | > `(lldb) po $arg1` 打印exception对象 60 | > 61 | > `(lldb) po [$arg1 name]` 打印异常名 62 | > 63 | > `(lldb)po [$arg1 reason]` 打印异常原因 64 | 65 | 66 | ### 6. lldb: Chisel 67 | 68 | [Chisel](https://github.com/facebook/chisel)是Facebook开源的一套扩展lldb的Python库,提供简单实用的调试命令.如`pvc`:打印当前`keywindow`的所有ViewController,`pviews`:递归地输出所有当前`keywindow`的所有`view`.等等,谁用谁知道. 69 | 70 | ### 7. 更多lldb命令可以`(lldb) help `中查看. 71 | 72 | 73 | ### 5. Xcode断点 74 | 75 | 断住某个断点时,可以通过拖动`程序执行指针`来更改代码执行顺序.如下图: 76 | 77 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/xode-debug-demo1.jpg) 78 | 79 | 80 | ### 6. 符号断点 81 | 82 | 当调试某些系统方法,或调试某个没有源码(或暂时没法儿用源码调试的)的framework时,举个例子: 83 | 84 | A.framework : 一个小的framework 85 | 86 | B.framework : 一个小的framework 87 | 88 | Lib.framework : 使用A.framework+B.framework+C.framework+.... 链接成一个最终的库. 89 | 90 | ApplicationDemo中使用Lib.framework. 要调试A.framework时,符号表断点就能派上用场了. 91 | 92 | 如下图,可以配合一些`lldb指令`来调试. 93 | 94 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/symbolic-breakpoint-demo.jpg) 95 | 96 | 97 | -------------------------------------------------------------------------------- /Articles/fucking-clang-warnings.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #搬运 [Which Clang Warning Is Generating This Message?](http://fuckingclangwarnings.com/) 4 | 5 | 6 | by [Matt Thompson](https://twitter.com/mattt) 7 | 8 | 9 |
10 | 11 | # Semantic Warnings 12 | 13 | | Warning | Message | 14 | | --- | --- | 15 | | -WCFString-literal | input conversion stopped due to an input byte that does not belong to the input codeset UTF-8 | 16 | | -WNSObject-attribute | __attribute ((NSObject)) may be put on a typedef only, attribute is ignored | 17 | | -Wabstract-vbase-init | initializer for virtual base class %0 of abstract class %1 will never be used | 18 | | -Waddress-of-array-temporary | pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression | 19 | | -Warc-maybe-repeated-use-of-weak | "weak %select{variable|property|implicit property|instance variable}0 %1 may be accessed multiple times in this %select{function|method|block|lambda}2 and may be unpredictably set to nil assign to a strong variable to keep the object alive | 20 | | -Warc-non-pod-memaccess | %select{destination for|source of}0 this %1 call is a pointer to ownership-qualified type %2 | 21 | | -Warc-performSelector-leaks | performSelector may cause a leak because its selector is unknown | 22 | | -Warc-repeated-use-of-weak | "weak %select{variable|property|implicit property|instance variable}0 %1 is accessed multiple times in this %select{function|method|block|lambda}2 but may be unpredictably set to nil assign to a strong variable to keep the object alive | 23 | | -Warc-retain-cycles | capturing %0 strongly in this block is likely to lead to a retain cycle | 24 | | -Warc-unsafe-retained-assign | assigning retained object to unsafe property object will be released after assignment | 25 | | -Warc-unsafe-retained-assign | assigning %select{array literal|dictionary literal|numeric literal|boxed expression|should not happen|block literal}0 to a weak %select{property|variable}1 object will be released after assignment | 26 | | -Warc-unsafe-retained-assign | assigning retained object to %select{weak|unsafe_unretained}0 %select{property|variable}1 object will be released after assignment | 27 | | -Warray-bounds | array index %0 is past the end of the array (which contains %1 element%s2) | 28 | | -Warray-bounds | array index %0 is before the beginning of the array | 29 | | -Warray-bounds | 'static' has no effect on zero-length arrays | 30 | | -Warray-bounds | array argument is too small contains %0 elements, callee requires at least %1 | 31 | | -Warray-bounds-pointer-arithmetic | the pointer incremented by %0 refers past the end of the array (that contains %1 element%s2) | 32 | | -Warray-bounds-pointer-arithmetic | the pointer decremented by %0 refers before the beginning of the array | 33 | | -Wassign-enum | integer constant not in range of enumerated type %0 | 34 | | -Watomic-property-with-user-defined-accessor | writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 with a user defined %select{getter|setter}2 | 35 | | -Wattributes | unknown attribute %0 ignored | 36 | | -Wauto-var-id | 'auto' deduced as 'id' in declaration of %0 | 37 | | -Wavailability | unknown platform %0 in availability macro | 38 | | -Wavailability | overriding method %select{introduced after|deprecated before|obsoleted before}0 overridden method on %1 (%2 vs. %3) | 39 | | -Wavailability | availability does not match previous declaration | 40 | | -Wavailability | overriding method cannot be unavailable on %0 when its overridden method is available | 41 | | -Wavailability | feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version %2 before it was %select{introduced|deprecated|obsoleted}3 in version %4 attribute ignored | 42 | | -Wbad-function-cast | cast from function call of type %0 to non-matching type %1 | 43 | | -Wbitfield-constant-conversion | implicit truncation from %2 to bitfield changes value from %0 to %1 | 44 | | -Wbitwise-op-parentheses | '&' within '|' | 45 | | -Wbool-conversion | "initialization of pointer of type %0 to null from a constant boolean " "expression | 46 | | -Wbridge-cast | %0 cannot bridge to %1 | 47 | | -Wbridge-cast | %0 bridges to %1, not %2 | 48 | | -Wbuiltin-requires-header | declaration of built-in function '%0' requires inclusion of the header stdio.h | 49 | | -Wbuiltin-requires-header | declaration of built-in function '%0' requires inclusion of the header setjmp.h | 50 | | -Wbuiltin-requires-header | declaration of built-in function '%0' requires inclusion of the header ucontext.h | 51 | | -Wc++-compat | %select{|empty }0%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++ | 52 | | -Wc++11-compat | explicit instantiation cannot be 'inline' | 53 | | -Wc++11-compat | explicit instantiation of %0 must occur at global scope | 54 | | -Wc++11-compat | explicit instantiation of %0 not in a namespace enclosing %1 | 55 | | -Wc++11-compat | explicit instantiation of %q0 must occur in namespace %1 | 56 | | -Wc++11-narrowing | constant expression evaluates to %0 which cannot be narrowed to type %1 in C++11 | 57 | | -Wc++11-narrowing | type %0 cannot be narrowed to %1 in initializer list in C++11 | 58 | | -Wc++11-narrowing | non-constant-expression cannot be narrowed from type %0 to %1 in initializer list in C++11 | 59 | | -Wc++98-c++11-compat | type definition in a constexpr %select{function|constructor}0 is incompatible with C++ standards before C++1y | 60 | | -Wc++98-c++11-compat | use of this statement in a constexpr %select{function|constructor}0 is incompatible with C++ standards before C++1y | 61 | | -Wc++98-c++11-compat | init-captures.def warn_cxx11_compat_init_capture : Warning "initialized lambda captures are incompatible with C++ standards " "before C++1y | 62 | | -Wc++98-c++11-compat | variable declaration in a constexpr %select{function|constructor}0 is incompatible with C++ standards before C++1y | 63 | | -Wc++98-c++11-compat | constexpr function with no return statements is incompatible with C++ standards before C++1y | 64 | | -Wc++98-c++11-compat | multiple return statements in constexpr function is incompatible with C++ standards before C++1y | 65 | | -Wc++98-c++11-compat | variable templates are incompatible with C++ standards before C++1y | 66 | | -Wc++98-compat | substitution failure due to access control is incompatible with C++98 | 67 | | -Wc++98-compat | %select{anonymous struct|union}0 member %1 with a non-trivial %select{constructor|copy constructor|move constructor|copy assignment operator|move assignment operator|destructor}2 is incompatible with C++98 | 68 | | -Wc++98-compat | enumeration type in nested name specifier is incompatible with C++98 | 69 | | -Wc++98-compat | static data member %0 in union is incompatible with C++98 | 70 | | -Wc++98-compat | default template arguments for a function template are incompatible with C++98 | 71 | | -Wc++98-compat | scalar initialized from empty initializer list is incompatible with C++98 | 72 | | -Wc++98-compat | befriending %1 without '%select{struct|interface|union|class|enum}0' keyword is incompatible with C++98 | 73 | | -Wc++98-compat | use of null pointer as non-type template argument is incompatible with C++98 | 74 | | -Wc++98-compat | friend declaration naming a member of the declaring class is incompatible with C++98 | 75 | | -Wc++98-compat | non-class friend type %0 is incompatible with C++98 | 76 | | -Wc++98-compat | befriending enumeration type %0 is incompatible with C++98 | 77 | | -Wc++98-compat | use of non-static data member %0 in an unevaluated context is incompatible with C++98 | 78 | | -Wc++98-compat | friend function %0 would be implicitly redefined in C++98 | 79 | | -Wc++98-compat | %select{class template|class template partial|variable template|variable template partial|function template|member function|static data member|member class|member enumeration}0 specialization of %1 outside namespace %2 is incompatible with C++98 | 80 | | -Wc++98-compat | reference initialized from initializer list is incompatible with C++98 | 81 | | -Wc++98-compat | redundant parentheses surrounding address non-type template argument are incompatible with C++98 | 82 | | -Wc++98-compat | initialization of initializer_list object is incompatible with C++98 | 83 | | -Wc++98-compat | use of 'template' keyword outside of a template is incompatible with C++98 | 84 | | -Wc++98-compat | non-type template argument referring to %select{function|object}0 %1 with internal linkage is incompatible with C++98 | 85 | | -Wc++98-compat | use of 'typename' outside of a template is incompatible with C++98 | 86 | | -Wc++98-compat | passing object of trivial but non-POD type %0 through variadic %select{function|block|method|constructor}1 is incompatible with C++98 | 87 | | -Wc++98-compat | goto would jump into protected scope in C++98 | 88 | | -Wc++98-compat | constructor call from initializer list is incompatible with C++98 | 89 | | -Wc++98-compat | 'auto' type specifier is incompatible with C++98 | 90 | | -Wc++98-compat | delegating constructors are incompatible with C++98 | 91 | | -Wc++98-compat | 'constexpr' specifier is incompatible with C++98 | 92 | | -Wc++98-compat | inheriting constructors are incompatible with C++98 | 93 | | -Wc++98-compat | explicit conversion functions are incompatible with C++98 | 94 | | -Wc++98-compat | switch case would be in a protected scope in C++98 | 95 | | -Wc++98-compat | '%0' type specifier is incompatible with C++98 | 96 | | -Wc++98-compat | indirect goto might cross protected scopes in C++98 | 97 | | -Wc++98-compat-pedantic | cast between pointer-to-function and pointer-to-object is incompatible with C++98 | 98 | | -Wc++98-compat-pedantic | implicit conversion from array size expression of type %0 to %select{integral|enumeration}1 type %2 is incompatible with C++98 | 99 | | -Wcast-align | cast from %0 to %1 increases required alignment from %2 to %3 | 100 | | -Wcast-of-sel-type | cast of type %0 to %1 is deprecated use sel_getName instead | 101 | | -Wchar-subscripts | array subscript is of type 'char' | 102 | | -Wconditional-uninitialized | variable %0 may be uninitialized when %select{used here|captured by block}1 | 103 | | -Wconstant-logical-operand | use of logical '%0' with constant operand | 104 | | -Wconstexpr-not-const | 'constexpr' non-static member function will not be implicitly 'const' in C++1y add 'const' to avoid a change in behavior | 105 | | -Wconsumed | state of variable '%0' must match at the entry and exit of loop | 106 | | -Wconsumed | parameter '%0' not in expected state when the function returns: expected '%1', observed '%2' | 107 | | -Wconsumed | argument not in expected state expected '%0', observed '%1' | 108 | | -Wconsumed | invalid invocation of method '%0' on a temporary object while it is in the '%1' state | 109 | | -Wconsumed | return state set for an unconsumable type '%0' | 110 | | -Wconsumed | consumed analysis attribute is attached to member of class '%0' which isn't marked as consumable | 111 | | -Wconsumed | invalid invocation of method '%0' on object '%1' while it is in the '%2' state | 112 | | -Wconsumed | return value not in expected state expected '%0', observed '%1' | 113 | | -Wconversion | implicit conversion discards imaginary component: %0 to %1 | 114 | | -Wconversion | non-type template argument with value '%0' converted to '%1' for unsigned template parameter of type %2 | 115 | | -Wconversion | implicit conversion loses floating-point precision: %0 to %1 | 116 | | -Wconversion | implicit conversion loses integer precision: %0 to %1 | 117 | | -Wconversion | non-type template argument value '%0' truncated to '%1' for template parameter of type %2 | 118 | | -Wconversion | implicit conversion turns vector to scalar: %0 to %1 | 119 | | -Wconversion | implicit conversion turns floating-point number into integer: %0 to %1 | 120 | | -Wcovered-switch-default | default label in switch which covers all enumeration values | 121 | | -Wcustom-atomic-properties | atomic by default property %0 has a user defined %select{getter|setter}1 (property should be marked 'atomic' if this is intended) | 122 | | -Wdangling-field | initializing pointer member %0 with the stack address of parameter %1 | 123 | | -Wdangling-field | binding reference %select{|subobject of }1member %0 to a temporary value | 124 | | -Wdangling-field | binding reference member %0 to stack allocated parameter %1 | 125 | | -Wdangling-initializer-list | array backing the initializer list will be destroyed at the end of %select{the full-expression|the constructor}0 | 126 | | -Wdelete-incomplete | deleting pointer to incomplete type %0 may cause undefined behavior | 127 | | -Wdelete-non-virtual-dtor | delete called on %0 that is abstract but has non-virtual destructor | 128 | | -Wdelete-non-virtual-dtor | delete called on %0 that has virtual functions but non-virtual destructor | 129 | | -Wdeprecated | access declarations are deprecated use using declarations instead | 130 | | -Wdeprecated | definition of implicit copy %select{constructor|assignment operator}1 for %0 is deprecated because it has a user-declared %select{copy %select{assignment operator|constructor}1|destructor}2 | 131 | | -Wdeprecated | dynamic exception specifications are deprecated | 132 | | -Wdeprecated-increment-bool | incrementing expression of type bool is deprecated | 133 | | -Wdeprecated-objc-isa-usage | assignment to Objective-C's isa is deprecated in favor of object_setClass() | 134 | | -Wdeprecated-objc-isa-usage | direct access to Objective-C's isa is deprecated in favor of object_getClass() | 135 | | -Wdeprecated-objc-pointer-introspection | bitmasking for introspection of Objective-C object pointers is strongly discouraged | 136 | | -Wdeprecated-objc-pointer-introspection-performSelector | warn_objc_pointer_masking.Text | 137 | | -Wdeprecated-writable-strings | dummy warning to enable -fconst-strings | 138 | | -Wdirect-ivar-access | instance variable %0 is being directly accessed | 139 | | -Wdistributed-object-modifiers | conflicting distributed object modifiers on return type in implementation of %0 | 140 | | -Wdistributed-object-modifiers | conflicting distributed object modifiers on parameter type in implementation of %0 | 141 | | -Wdivision-by-zero | division by zero is undefined | 142 | | -Wdivision-by-zero | remainder by zero is undefined | 143 | | -Wdocumentation | parameter '%0' not found in the function declaration | 144 | | -Wdocumentation | not a Doxygen trailing comment | 145 | | -Wduplicate-enum | element %0 has been implicitly assigned %1 which another element has been assigned | 146 | | -Wduplicate-method-match | multiple declarations of method %0 found and ignored | 147 | | -Wdynamic-class-memaccess | %select{destination for|source of|first operand of|second operand of}0 this %1 call is a pointer to dynamic class %2 vtable pointer will be %select{overwritten|copied|moved|compared}3 | 148 | | -Wempty-body | switch statement has empty body | 149 | | -Wempty-body | for loop has empty body | 150 | | -Wempty-body | if statement has empty body | 151 | | -Wempty-body | range-based for loop has empty body | 152 | | -Wempty-body | while loop has empty body | 153 | | -Wenum-compare | comparison of two values with different enumeration types%diff{ ($ and $)|}0,1 | 154 | | -Wenum-conversion | implicit conversion from enumeration type %0 to different enumeration type %1 | 155 | | -Wexit-time-destructors | declaration requires an exit-time destructor | 156 | | -Wexplicit-ownership-type | method parameter of type %0 with no explicit ownership | 157 | | -Wextern-c-compat | %select{|empty }0%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++ | 158 | | -Wextern-initializer | 'extern' variable has an initializer | 159 | | -Wfloat-equal | comparing floating point with == or != is unsafe | 160 | | -Wformat | "data argument position '%0' exceeds the number of data arguments (%1) | 161 | | -Wformat | position arguments in format strings start counting at 1 (not 0) | 162 | | -Wformat | invalid position specified for %select{field width|field precision}0 | 163 | | -Wformat | cannot mix positional and non-positional arguments in format string | 164 | | -Wformat | values of type '%0' should not be used as format arguments add an explicit cast to %1 instead | 165 | | -Wformat | format specifies type %0 but the argument has type %1 | 166 | | -Wformat | zero field width in scanf format string is unused | 167 | | -Wformat | no closing ']' for '%%[' in scanf format string | 168 | | -Wformat | format string should not be a wide string | 169 | | -Wformat | format string contains '\\0' within the string body | 170 | | -Wformat | '%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument | 171 | | -Wformat | field %select{width|precision}0 should have type %1, but argument has type %2 | 172 | | -Wformat | %select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior | 173 | | -Wformat | format string missing | 174 | | -Wformat | incomplete format specifier | 175 | | -Wformat | flag '%0' results in undefined behavior with '%1' conversion specifier | 176 | | -Wformat | flag '%0' is ignored when flag '%1' is present | 177 | | -Wformat | more '%%' conversions than data arguments | 178 | | -Wformat | length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier | 179 | | -Wformat-extra-args | data argument not used by format string | 180 | | -Wformat-invalid-specifier | invalid conversion specifier '%0' | 181 | | -Wformat-nonliteral | format string is not a string literal | 182 | | -Wformat-security | format string is not a string literal (potentially insecure) | 183 | | -Wformat-zero-length | format string is empty | 184 | | -Wgcc-compat | GCC does not allow the 'cleanup' attribute argument to be anything other than a simple identifier | 185 | | -Wglobal-constructors | declaration requires a global constructor | 186 | | -Wglobal-constructors | declaration requires a global destructor | 187 | | -Wgnu-conditional-omitted-operand | use of GNU ?: conditional expression extension, omitting middle operand | 188 | | -Wheader-hygiene | using namespace directive in global context in header | 189 | | -Widiomatic-parentheses | using the result of an assignment as a condition without parentheses | 190 | | -Wignored-attributes | 'malloc' attribute only applies to functions returning a pointer type | 191 | | -Wignored-attributes | %0 attribute only applies to %select{functions|unions|variables and functions|functions and methods|parameters|functions, methods and blocks|functions, methods, and classes|functions, methods, and parameters|classes|variables|methods|variables, functions and labels|fields and global variables|structs|variables, functions and tag types|thread-local variables|variables and fields|variables, data members and tag types|types and namespaces|Objective-C interfaces}1 | 192 | | -Wignored-attributes | '%0' attribute cannot be specified on a definition | 193 | | -Wignored-attributes | __weak attribute cannot be specified on an automatic variable when ARC is not enabled | 194 | | -Wignored-attributes | Objective-C GC does not allow weak variables on the stack | 195 | | -Wignored-attributes | __weak attribute cannot be specified on a field declaration | 196 | | -Wignored-attributes | attribute %0 cannot be applied to %select{functions|Objective-C method}1 without return value | 197 | | -Wignored-attributes | attribute declaration must precede definition | 198 | | -Wignored-attributes | attribute %0 is ignored, place it after \"%select{class|struct|union|interface|enum}1\" to apply attribute to type declaration | 199 | | -Wignored-attributes | __declspec attribute %0 is not supported | 200 | | -Wignored-attributes | attribute %0 ignored, because it cannot be applied to a type | 201 | | -Wignored-attributes | attribute %0 after definition is ignored | 202 | | -Wignored-attributes | %0 attribute ignored | 203 | | -Wignored-attributes | 'sentinel' attribute only supported for variadic %select{functions|blocks}0 | 204 | | -Wignored-attributes | 'sentinel' attribute requires named arguments | 205 | | -Wignored-attributes | '%0' only applies to %select{function|pointer|Objective-C object or block pointer}1 types type here is %2 | 206 | | -Wignored-attributes | 'nonnull' attribute applied to function with no pointer arguments | 207 | | -Wignored-attributes | %0 attribute can only be applied to instance variables or properties | 208 | | -Wignored-attributes | ibaction attribute can only be applied to Objective-C instance methods | 209 | | -Wignored-attributes | %0 calling convention ignored on variadic function | 210 | | -Wignored-attributes | %0 only applies to variables with static storage duration and functions | 211 | | -Wignored-attributes | %0 attribute argument not supported: %1 | 212 | | -Wignored-attributes | #pramga ms_struct can not be used with dynamic classes or structures | 213 | | -Wignored-attributes | transparent union definition must contain at least one field transparent_union attribute ignored | 214 | | -Wignored-attributes | first field of a transparent union cannot have %select{floating point|vector}0 type %1 transparent_union attribute ignored | 215 | | -Wignored-attributes | 'gnu_inline' attribute requires function to be marked 'inline', attribute ignored | 216 | | -Wignored-attributes | calling convention %0 ignored for this target | 217 | | -Wignored-attributes | transparent_union attribute can only be applied to a union definition attribute ignored | 218 | | -Wignored-attributes | %select{alignment|size}0 of field %1 (%2 bits) does not match the %select{alignment|size}0 of the first field in transparent union transparent_union attribute ignored | 219 | | -Wignored-attributes | attribute %0 is already applied | 220 | | -Wignored-attributes | %0 attribute ignored for field of type %1 | 221 | | -Wignored-attributes | %0 attribute ignored when parsing type | 222 | | -Wignored-attributes | %0 attribute only applies to %select{functions|methods|properties}1 that return %select{an Objective-C object|a pointer|a non-retainable pointer}2 | 223 | | -Wignored-attributes | %0 attribute only applies to %select{Objective-C object|pointer}1 parameters | 224 | | -Wignored-attributes | attribute %0 is already applied with different parameters | 225 | | -Wignored-attributes | unknown visibility %0 | 226 | | -Wignored-qualifiers | "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect | 227 | | -Wignored-qualifiers | ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 lifetime qualifier on return type is ignored | 228 | | -Wimplicit-atomic-properties | property is assumed atomic by default | 229 | | -Wimplicit-atomic-properties | property is assumed atomic when auto-synthesizing the property | 230 | | -Wimplicit-fallthrough | fallthrough annotation in unreachable code | 231 | | -Wimplicit-fallthrough | unannotated fall-through between switch labels | 232 | | -Wimplicit-fallthrough | fallthrough annotation does not directly precede switch label | 233 | | -Wimplicit-function-declaration | implicit declaration of function %0 | 234 | | -Wimplicit-function-declaration | use of unknown builtin %0 | 235 | | -Wimplicit-retain-self | "block implicitly retains 'self' explicitly mention 'self' to indicate this is intended behavior | 236 | | -Wincompatible-library-redeclaration | incompatible redeclaration of library function %0 | 237 | | -Wincomplete-implementation | method definition for %0 not found | 238 | | -Winherited-variadic-ctor | inheriting constructor does not inherit ellipsis | 239 | | -Winitializer-overrides | subobject initialization overrides initialization of other fields within its enclosing subobject | 240 | | -Winitializer-overrides | initializer overrides prior initialization of this subobject | 241 | | -Wint-to-pointer-cast | cast to %1 from smaller integer type %0 | 242 | | -Wint-to-void-pointer-cast | cast to %1 from smaller integer type %0 | 243 | | -Winvalid-iboutlet | IBOutletCollection properties should be copy/strong and not assign | 244 | | -Winvalid-iboutlet | %select{instance variable|property}2 with %0 attribute must be an object type (invalid %1) | 245 | | -Winvalid-noreturn | function %0 declared 'noreturn' should not return | 246 | | -Winvalid-noreturn | function declared 'noreturn' should not return | 247 | | -Wlarge-by-value-copy | return value of %0 is a large (%1 bytes) pass-by-value object pass it by reference instead ? | 248 | | -Wlarge-by-value-copy | %0 is a large (%1 bytes) pass-by-value argument pass it by reference instead ? | 249 | | -Wliteral-conversion | implicit conversion from %0 to %1 changes value from %2 to %3 | 250 | | -Wliteral-range | magnitude of floating-point constant too large for type %0 maximum is %1 | 251 | | -Wliteral-range | magnitude of floating-point constant too small for type %0 minimum is %1 | 252 | | -Wlogical-not-parentheses | logical not is only applied to the left hand side of this comparison | 253 | | -Wlogical-op-parentheses | '&&' within '||' | 254 | | -Wloop-analysis | variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 used in loop condition not modified in loop body | 255 | | -Wloop-analysis | variable %0 is %select{decremented|incremented}1 both in the loop header and in the loop body | 256 | | -Wmethod-signatures | conflicting parameter types in implementation of %0: %1 vs %2 | 257 | | -Wmethod-signatures | conflicting return type in implementation of %0: %1 vs %2 | 258 | | -Wmicrosoft | extra qualification on member %0 | 259 | | -Wmismatched-method-attributes | attributes on method implementation and its declaration must match | 260 | | -Wmismatched-parameter-types | conflicting parameter types in implementation of %0%diff{: $ vs $|}1,2 | 261 | | -Wmismatched-return-types | conflicting return type in implementation of %0%diff{: $ vs $|}1,2 | 262 | | -Wmissing-braces | suggest braces around initialization of subobject | 263 | | -Wmissing-declarations | '%0' ignored on this declaration | 264 | | -Wmissing-field-initializers | missing field '%0' initializer | 265 | | -Wmissing-method-return-type | method has no return type specified defaults to 'id' | 266 | | -Wmissing-noreturn | %select{function|method}0 %1 could be declared with attribute 'noreturn' | 267 | | -Wmissing-noreturn | block could be declared with attribute 'noreturn' | 268 | | -Wmissing-prototypes | no previous prototype for function %0 | 269 | | -Wmissing-variable-declarations | no previous extern declaration for non-static variable %0 | 270 | | -Wmultiple-move-vbase | defaulted move assignment operator of %0 will move assign virtual base class %1 multiple times | 271 | | -Wnested-anon-types | anonymous types declared in an anonymous union/struct are an extension | 272 | | -Wno-typedef-redefinition | Redefinition of typedef '%0' is a C11 feature | 273 | | -Wnon-literal-null-conversion | "expression which evaluates to zero treated as a null pointer constant of " "type %0 | 274 | | -Wnon-pod-varargs | second argument to 'va_arg' is of ARC ownership-qualified type %0 | 275 | | -Wnon-pod-varargs | cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic %select{function|block|method|constructor}2 expected type from format string was %3 | 276 | | -Wnon-pod-varargs | second argument to 'va_arg' is of non-POD type %0 | 277 | | -Wnon-pod-varargs | cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic %select{function|block|method|constructor}2 call will abort at runtime | 278 | | -Wnon-virtual-dtor | %0 has virtual functions but non-virtual destructor | 279 | | -Wnonnull | null passed to a callee which requires a non-null argument | 280 | | -Wnull-arithmetic | use of NULL in arithmetic operation | 281 | | -Wnull-arithmetic | comparison between NULL and non-pointer %select{(%1 and NULL)|(NULL and %1)}0 | 282 | | -Wnull-dereference | indirection of non-volatile null pointer will be deleted, not trap | 283 | | -Wobjc-autosynthesis-property-ivar-name-match | autosynthesized property %0 will use %select{|synthesized}1 instance variable %2, not existing instance variable %3 | 284 | | -Wobjc-forward-class-redefinition | redefinition of forward class %0 of a typedef name of an object type is ignored | 285 | | -Wobjc-interface-ivars | declaration of instance variables in the interface is deprecated | 286 | | -Wobjc-literal-compare | direct comparison of %select{an array literal|a dictionary literal|a numeric literal|a boxed expression|}0 has undefined behavior | 287 | | -Wobjc-literal-missing-atsign | string literal must be prefixed by '@' | 288 | | -Wobjc-method-access | instance method %objcinstance0 not found (return type defaults to 'id') did you mean %objcinstance2? | 289 | | -Wobjc-method-access | class method %objcclass0 not found (return type defaults to 'id') did you mean %objcclass2? | 290 | | -Wobjc-method-access | instance method %objcinstance0 not found (return type defaults to 'id') | 291 | | -Wobjc-method-access | instance method %0 is being used on 'Class' which is not in the root class | 292 | | -Wobjc-method-access | class method %objcclass0 not found (return type defaults to 'id') | 293 | | -Wobjc-method-access | instance method %0 found instead of class method %1 | 294 | | -Wobjc-missing-property-synthesis | "auto property synthesis is synthesizing property not explicitly synthesized | 295 | | -Wobjc-missing-super-calls | method possibly missing a [super %0] call | 296 | | -Wobjc-noncopy-retain-block-property | "retain'ed block property does not copy the block " "- use copy attribute instead | 297 | | -Wobjc-nonunified-exceptions | can not catch an exception thrown with @throw in C++ in the non-unified exception model | 298 | | -Wobjc-property-implementation | property %0 requires method %1 to be defined - use @dynamic or provide a method implementation in this category | 299 | | -Wobjc-property-implementation | property %0 requires method %1 to be defined - use @synthesize, @dynamic or provide a method implementation in this class implementation | 300 | | -Wobjc-property-implicit-mismatch | "primary property declaration is implicitly strong while redeclaration in class extension is weak | 301 | | -Wobjc-property-matches-cocoa-ownership-rule | property's synthesized getter follows Cocoa naming convention for returning 'owned' objects | 302 | | -Wobjc-property-no-attribute | no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed | 303 | | -Wobjc-property-no-attribute | default property attribute 'assign' not appropriate for non-GC object | 304 | | -Wobjc-property-synthesis | auto property synthesis will not synthesize property '%0' because it is 'readwrite' but it will be synthesized 'readonly' via another property | 305 | | -Wobjc-property-synthesis | "auto property synthesis will not synthesize property '%0' because it cannot share an ivar with another synthesized property | 306 | | -Wobjc-protocol-method-implementation | category is implementing a method which will also be implemented by its primary class | 307 | | -Wobjc-protocol-property-synthesis | auto property synthesis will not synthesize property declared in a protocol | 308 | | -Wobjc-redundant-literal-use | using %0 with a literal is redundant | 309 | | -Wobjc-root-class | class %0 defined without specifying a base class | 310 | | -Wobjc-string-compare | direct comparison of a string literal has undefined behavior | 311 | | -Wobjc-string-concatenation | concatenated NSString literal for an NSArray expression - possibly missing a comma | 312 | | -Wover-aligned | type %0 requires %1 bytes of alignment and the default allocator only guarantees %2 bytes | 313 | | -Woverloaded-shift-op-parentheses | overloaded operator %select{|}0 has lower precedence than comparison operator | 314 | | -Woverloaded-virtual | %q0 hides overloaded virtual %select{function|functions}1 | 315 | | -Woverriding-method-mismatch | conflicting distributed object modifiers on parameter type in declaration of %0 | 316 | | -Woverriding-method-mismatch | conflicting parameter types in declaration of %0: %1 vs %2 | 317 | | -Woverriding-method-mismatch | conflicting variadic declaration of method and its implementation | 318 | | -Woverriding-method-mismatch | conflicting distributed object modifiers on return type in declaration of %0 | 319 | | -Woverriding-method-mismatch | conflicting parameter types in declaration of %0%diff{: $ vs $|}1,2 | 320 | | -Woverriding-method-mismatch | conflicting return type in declaration of %0%diff{: $ vs $|}1,2 | 321 | | -Woverriding-method-mismatch | conflicting return type in declaration of %0: %1 vs %2 | 322 | | -Wpacked | packed attribute is unnecessary for %0 | 323 | | -Wpadded | padding %select{struct|interface|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 to align anonymous bit-field | 324 | | -Wpadded | padding %select{struct|interface|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 to align %5 | 325 | | -Wpadded | padding size of %0 with %1 %select{byte|bit}2%select{|s}3 to alignment boundary | 326 | | -Wparentheses | using the result of an assignment as a condition without parentheses | 327 | | -Wparentheses | %0 has lower precedence than %1 %1 will be evaluated first | 328 | | -Wparentheses | operator '?:' has lower precedence than '%0' '%0' will be evaluated first | 329 | | -Wparentheses-equality | equality comparison with extraneous parentheses | 330 | | -Wpointer-arith | subtraction of pointers to type %0 of zero size has undefined behavior | 331 | | -Wpredefined-identifier-outside-function | predefined identifier is only valid inside function | 332 | | -Wprivate-extern | use of __private_extern__ on a declaration may not produce external symbol private to the linkage unit and is deprecated | 333 | | -Wprotocol | method %0 in protocol not implemented | 334 | | -Wprotocol-property-synthesis-ambiguity | property of type %0 was selected for synthesis | 335 | | -Wreadonly-iboutlet-property | readonly IBOutlet property '%0' when auto-synthesized may not work correctly with 'nib' loader | 336 | | -Wreadonly-setter-attrs | property attributes '%0' and '%1' are mutually exclusive | 337 | | -Wreceiver-expr | receiver type %0 is not 'id' or interface pointer, consider casting it to 'id' | 338 | | -Wreceiver-forward-class | receiver type %0 for instance message is a forward declaration | 339 | | -Wreceiver-is-weak | "weak %select{receiver|property|implicit property}0 may be unpredictably set to nil | 340 | | -Wreinterpret-base-class | 'reinterpret_cast' %select{from|to}3 class %0 %select{to|from}3 its %select{virtual base|base at non-zero offset}2 %1 behaves differently from 'static_cast' | 341 | | -Wreorder | %select{field|base class}0 %1 will be initialized after %select{field|base}2 %3 | 342 | | -Wrequires-super-attribute | %0 attribute cannot be applied to %select{methods in protocols|dealloc}1 | 343 | | -Wreturn-stack-address | returning address of local temporary object | 344 | | -Wreturn-stack-address | returning address of label, which is local | 345 | | -Wreturn-stack-address | address of stack memory associated with local variable %0 returned | 346 | | -Wreturn-stack-address | reference to stack memory associated with local variable %0 returned | 347 | | -Wreturn-stack-address | returning reference to local temporary object | 348 | | -Wreturn-type | control may reach end of non-void function | 349 | | -Wreturn-type | non-void %select{function|method}1 %0 should return a value, DefaultError | 350 | | -Wreturn-type | control reaches end of non-void function | 351 | | -Wreturn-type-c-linkage | %0 has C-linkage specified, but returns incomplete type %1 which could be incompatible with C | 352 | | -Wreturn-type-c-linkage | %0 has C-linkage specified, but returns user-defined type %1 which is incompatible with C | 353 | | -Wsection | section does not match previous declaration | 354 | | -Wselector | creating selector for nonexistent method %0 | 355 | | -Wselector-type-mismatch | multiple selectors named %0 found | 356 | | -Wself-assign | explicitly assigning a variable of type %0 to itself | 357 | | -Wself-assign-field | assigning %select{field|instance variable}0 to itself | 358 | | -Wsentinel | "missing sentinel in %select{function call|method dispatch|block call}0 | 359 | | -Wsentinel | not enough variable arguments in %0 declaration to fit a sentinel | 360 | | -Wshadow | declaration shadows a %select{" "local variable|" "variable in %2|" "static data member of %2|" "field of %2}1 | 361 | | -Wshadow-ivar | local declaration of %0 hides instance variable | 362 | | -Wshift-count-negative | shift count is negative | 363 | | -Wshift-count-overflow | shift count = width of type | 364 | | -Wshift-op-parentheses | operator '%0' has lower precedence than '%1' '%1' will be evaluated first | 365 | | -Wshift-overflow | signed shift result (%0) requires %1 bits to represent, but %2 only has %3 bits | 366 | | -Wshift-sign-overflow | signed shift result (%0) sets the sign bit of the shift expression's type (%1) and becomes negative | 367 | | -Wshorten-64-to-32 | implicit conversion loses integer precision: %0 to %1 | 368 | | -Wsign-compare | comparison of integers of different signs: %0 and %1 | 369 | | -Wsign-conversion | implicit conversion changes signedness: %0 to %1 | 370 | | -Wsign-conversion | operand of ? changes signedness: %0 to %1 | 371 | | -Wsizeof-array-argument | sizeof on array function parameter will return size of %0 instead of %1 | 372 | | -Wsizeof-array-decay | sizeof on pointer operation will return size of %0 instead of %1 | 373 | | -Wsizeof-pointer-memaccess | '%0' call operates on objects of type %1 while the size is based on a " "different type %2 | 374 | | -Wsizeof-pointer-memaccess | argument to 'sizeof' in %0 call is the same pointer type %1 as the %select{destination|source}2 expected %3 or an explicit length | 375 | | -Wsometimes-uninitialized | variable %0 is %select{used|captured}1 uninitialized whenever %select{'%3' condition is %select{true|false}4|'%3' loop %select{is entered|exits because its condition is false}4|'%3' loop %select{condition is true|exits because its condition is false}4|switch %3 is taken|its declaration is reached|%3 is called}2 | 376 | | -Wstatic-local-in-inline | non-constant static local variable in inline function may be different in different files | 377 | | -Wstatic-self-init | static variable %0 is suspiciously used within its own initialization | 378 | | -Wstrict-selector-match | multiple methods named %0 found | 379 | | -Wstring-compare | result of comparison against %select{a string literal|@encode}0 is unspecified (use strncmp instead) | 380 | | -Wstring-conversion | implicit conversion turns string literal into bool: %0 to %1 | 381 | | -Wstring-plus-char | adding %0 to a string pointer does not append to the string | 382 | | -Wstring-plus-int | adding %0 to a string does not append to the string | 383 | | -Wstrlcpy-strlcat-size | size argument in %0 call appears to be size of the source expected the size of the destination | 384 | | -Wstrncat-size | the value of the size argument in 'strncat' is too large, might lead to a " "buffer overflow | 385 | | -Wstrncat-size | size argument in 'strncat' call appears " "to be size of the source | 386 | | -Wstrncat-size | the value of the size argument to 'strncat' is wrong | 387 | | -Wsuper-class-method-mismatch | method parameter type %diff{$ does not match super class method parameter type $|does not match super class method parameter type}0,1 | 388 | | -Wswitch | overflow converting case value to switch condition type (%0 to %1) | 389 | | -Wswitch | case value not in enumerated type %0 | 390 | | -Wswitch | %0 enumeration values not handled in switch: %1, %2, %3... | 391 | | -Wswitch | enumeration values %0 and %1 not handled in switch | 392 | | -Wswitch | enumeration value %0 not handled in switch | 393 | | -Wswitch | enumeration values %0, %1, and %2 not handled in switch | 394 | | -Wswitch-enum | enumeration values %0, %1, and %2 not explicitly handled in switch | 395 | | -Wswitch-enum | enumeration values %0 and %1 not explicitly handled in switch | 396 | | -Wswitch-enum | %0 enumeration values not explicitly handled in switch: %1, %2, %3... | 397 | | -Wswitch-enum | enumeration value %0 not explicitly handled in switch | 398 | | -Wtautological-compare | comparison of %0 unsigned%select{| enum}2 expression is always %1 | 399 | | -Wtautological-compare | %select{self-|array }0comparison always evaluates to %select{false|true|a constant}1 | 400 | | -Wtautological-compare | comparison of unsigned%select{| enum}2 expression %0 is always %1 | 401 | | -Wtautological-constant-out-of-range-compare | comparison of constant %0 with expression of type %1 is always %select{false|true}2 | 402 | | -Wthread-safety-analysis | locking '%0' that is already locked | 403 | | -Wthread-safety-analysis | cannot call function '%0' while mutex '%1' is locked | 404 | | -Wthread-safety-analysis | %select{reading|writing}2 the value pointed to by '%0' requires locking %select{'%1'|'%1' exclusively}2 | 405 | | -Wthread-safety-analysis | unlocking '%0' that was not locked | 406 | | -Wthread-safety-analysis | mutex '%0' is locked exclusively and shared in the same scope | 407 | | -Wthread-safety-analysis | calling function '%0' requires %select{shared|exclusive}2 lock on '%1' | 408 | | -Wthread-safety-analysis | %select{reading|writing}2 variable '%0' requires locking %select{'%1'|'%1' exclusively}2 | 409 | | -Wthread-safety-analysis | cannot resolve lock expression | 410 | | -Wthread-safety-analysis | expecting mutex '%0' to be locked at the end of function | 411 | | -Wthread-safety-analysis | mutex '%0' is not locked on every path through here | 412 | | -Wthread-safety-analysis | %select{reading|writing}1 the value pointed to by '%0' requires locking %select{any mutex|any mutex exclusively}1 | 413 | | -Wthread-safety-analysis | %select{reading|writing}1 variable '%0' requires locking %select{any mutex|any mutex exclusively}1 | 414 | | -Wthread-safety-analysis | mutex '%0' is still locked at the end of function | 415 | | -Wthread-safety-analysis | expecting mutex '%0' to be locked at start of each loop | 416 | | -Wthread-safety-attributes | ignoring %0 attribute because its argument is invalid | 417 | | -Wthread-safety-attributes | %0 attribute only applies to %select{fields and global variables|functions and methods|classes and structs}1 | 418 | | -Wthread-safety-attributes | %0 attribute requires arguments that are class type or point to class type type here is '%1' | 419 | | -Wthread-safety-attributes | %0 attribute can only be applied in a context annotated with 'lockable' attribute | 420 | | -Wthread-safety-attributes | %0 attribute requires arguments whose type is annotated with 'lockable' attribute type here is '%1' | 421 | | -Wthread-safety-attributes | '%0' only applies to pointer types type here is %1 | 422 | | -Wthread-safety-beta | Thread safety beta warning. | 423 | | -Wthread-safety-precise | %select{reading|writing}2 the value pointed to by '%0' requires locking %select{'%1'|'%1' exclusively}2 | 424 | | -Wthread-safety-precise | %select{reading|writing}2 variable '%0' requires locking %select{'%1'|'%1' exclusively}2 | 425 | | -Wthread-safety-precise | calling function '%0' requires %select{shared|exclusive}2 lock on '%1' | 426 | | -Wtype-safety | this type tag was not designed to be used with this function | 427 | | -Wtype-safety | specified %0 type tag requires a null pointer | 428 | | -Wtype-safety | argument type %0 doesn't match specified '%1' type tag %select{that requires %3|}2 | 429 | | -Wundeclared-selector | undeclared selector %0 did you mean %1? | 430 | | -Wundeclared-selector | undeclared selector %0 | 431 | | -Wundefined-inline | inline function %q0 is not defined | 432 | | -Wundefined-internal | %select{function|variable}0 %q1 has internal linkage but is not defined | 433 | | -Wundefined-reinterpret-cast | dereference of type %1 that was reinterpret_cast from type %0 has undefined behavior | 434 | | -Wundefined-reinterpret-cast | reinterpret_cast from %0 to %1 has undefined behavior | 435 | | -Wuninitialized | reference %0 is not yet bound to a value when used within its own initialization | 436 | | -Wuninitialized | field %0 is uninitialized when used here | 437 | | -Wuninitialized | block pointer variable %0 is uninitialized when captured by block | 438 | | -Wuninitialized | variable %0 is uninitialized when used within its own initialization | 439 | | -Wuninitialized | variable %0 is uninitialized when %select{used here|captured by block}1 | 440 | | -Wuninitialized | reference %0 is not yet bound to a value when used here | 441 | | -Wunneeded-internal-declaration | %select{function|variable}0 %1 is not needed and will not be emitted | 442 | | -Wunneeded-internal-declaration | 'static' function %0 declared in header file should be declared 'static inline' | 443 | | -Wunneeded-member-function | member function %0 is not needed and will not be emitted | 444 | | -Wunreachable-code | will never be executed | 445 | | -Wunsequenced | multiple unsequenced modifications to %0 | 446 | | -Wunsequenced | unsequenced modification and access to %0 | 447 | | -Wunsupported-friend | dependent nested name specifier '%0' for friend template declaration is not supported ignoring this friend declaration | 448 | | -Wunsupported-friend | dependent nested name specifier '%0' for friend class declaration is not supported turning off access control for %1 | 449 | | -Wunsupported-visibility | target does not support 'protected' visibility using 'default' | 450 | | -Wunused-comparison | %select{equality|inequality}0 comparison result unused | 451 | | -Wunused-const-variable | unused variable %0 | 452 | | -Wunused-exception-parameter | unused exception parameter %0 | 453 | | -Wunused-function | unused function %0 | 454 | | -Wunused-label | unused label %0 | 455 | | -Wunused-member-function | unused member function %0 | 456 | | -Wunused-parameter | unused parameter %0 | 457 | | -Wunused-private-field | private field %0 is not used | 458 | | -Wunused-property-ivar | ivar %0 which backs the property is not referenced in this property's accessor | 459 | | -Wunused-result | ignoring return value of function declared with warn_unused_result attribute | 460 | | -Wunused-value | ignoring return value of function declared with %0 attribute | 461 | | -Wunused-value | expression result unused should this cast be to 'void'? | 462 | | -Wunused-value | expression result unused | 463 | | -Wunused-variable | unused variable %0 | 464 | | -Wunused-volatile-lvalue | expression result unused assign into a variable to force a volatile load | 465 | | -Wused-but-marked-unused | %0 was marked unused but was used | 466 | | -Wuser-defined-literals | user-defined literal suffixes not starting with '_' are reserved%select{ no literal will invoke this operator|}0 | 467 | | -Wvarargs | second parameter of 'va_start' not last named argument | 468 | | -Wvarargs | 'va_start' has undefined behavior with reference types | 469 | | -Wvarargs | second argument to 'va_arg' is of promotable type %0 this va_arg has undefined behavior because arguments will be promoted to %1 | 470 | | -Wvector-conversion | incompatible vector types %select{%diff{assigning to $ from $|assigning to different types}0,1|%diff{passing $ to parameter of type $|passing to parameter of different type}0,1|%diff{returning $ from a function with result type $|returning from function with different return type}0,1|%diff{converting $ to type $|converting between types}0,1|%diff{initializing $ with an expression of type $|initializing with expression of different type}0,1|%diff{sending $ to parameter of type $|sending to parameter of different type}0,1|%diff{casting $ to type $|casting between types}0,1}2 | 471 | | -Wvexing-parse | parentheses were disambiguated as a function declaration | 472 | | -Wvexing-parse | empty parentheses interpreted as a function declaration | 473 | | -Wvisibility | declaration of %0 will not be visible outside of this function | 474 | | -Wvisibility | redefinition of %0 will not be visible outside of this function | 475 | | -Wvla | variable length array used | 476 | | -Wvla-extension | variable length arrays are a C99 feature | 477 | | -Wweak-template-vtables | explicit template instantiation %0 will emit a vtable in every translation unit | 478 | | -Wweak-vtables | %0 has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit | 479 | 480 |
481 | 482 |
483 | 484 | # Lexer Warnings 485 | 486 | | Warning | Message | 487 | | --- | --- | 488 | | -W#pragma-messages | %0 | 489 | | -W#warnings | %0 | 490 | | -W#warnings | %0 | 491 | | -Wambiguous-macro | ambiguous expansion of macro %0 | 492 | | -Wauto-import | treating #%select{include|import|include_next|__include_macros}0 as an import of module '%1' | 493 | | -Wbackslash-newline-escape | backslash and newline separated by space | 494 | | -Wc++11-compat | identifier after literal will be treated as a user-defined literal suffix in C++11 | 495 | | -Wc++11-compat | '%0' is a keyword in C++11 | 496 | | -Wc++98-c++11-compat | digit separators are incompatible with C++ standards before C++1y | 497 | | -Wc++98-c++11-compat-pedantic | binary integer literals are incompatible with C++ standards before C++1y | 498 | | -Wc++98-compat | raw string literals are incompatible with C++98 | 499 | | -Wc++98-compat | unicode literals are incompatible with C++98 | 500 | | -Wc++98-compat | universal character name referring to a control character is incompatible with C++98 | 501 | | -Wc++98-compat | '::' is treated as digraph ':' (aka '[') followed by ':' in C++98 | 502 | | -Wc++98-compat | using this character in an identifier is incompatible with C++98 | 503 | | -Wc++98-compat | specifying character '%0' with a universal character name is incompatible with C++98 | 504 | | -Wc++98-compat-pedantic | variadic macros are incompatible with C++98 | 505 | | -Wc++98-compat-pedantic | #line number greater than 32767 is incompatible with C++98 | 506 | | -Wc++98-compat-pedantic | C++98 requires newline at end of file | 507 | | -Wc++98-compat-pedantic | empty macro arguments are incompatible with C++98 | 508 | | -Wc99-compat | unicode literals are incompatible with C99 | 509 | | -Wc99-compat | %select{using this character in an identifier|starting an identifier with this character}0 is incompatible with C99 | 510 | | -Wcomment | '/*' within block comment | 511 | | -Wcomment | escaped newline between */ characters at block comment end | 512 | | -Wdisabled-macro-expansion | disabled expansion of recursive macro | 513 | | -Wheader-guard | %0 is used as a header guard here, followed by #define of a different macro | 514 | | -Wignored-attributes | unknown attribute '%0' | 515 | | -Wincomplete-module | header '%0' is included in module '%1' but not listed in module map | 516 | | -Wincomplete-umbrella | umbrella header for module '%0' does not include header '%1' | 517 | | -Winvalid-token-paste | pasting formed '%0', an invalid preprocessing token, DefaultError | 518 | | -Wmalformed-warning-check | __has_warning expected option name (e.g. \"-Wundef\") | 519 | | -Wnewline-eof | no newline at end of file | 520 | | -Wnull-character | null character ignored | 521 | | -Wnull-character | null character(s) preserved in string literal | 522 | | -Wnull-character | null character(s) preserved in character literal | 523 | | -Wtrigraphs | ignored trigraph would end block comment | 524 | | -Wtrigraphs | trigraph ignored | 525 | | -Wundef | %0 is not defined, evaluates to 0 | 526 | | -Wunicode | universal character names are only valid in C99 or C++ treating as '\\' followed by identifier | 527 | | -Wunicode | \\%0 used with no following hex digits treating as '\\' followed by identifier | 528 | | -Wunicode | incomplete universal character name treating as '\\' followed by identifier | 529 | | -Wunicode | universal character name refers to a surrogate character | 530 | | -Wunknown-pragmas | unknown pragma ignored | 531 | | -Wunknown-pragmas | pragma STDC FENV_ACCESS ON is not supported, ignoring pragma | 532 | | -Wunused-macros | macro is not used | 533 | 534 |
535 | 536 | 537 |
538 | 539 | # Parser Warnings 540 | 541 | | Warning | Message | 542 | | --- | --- | 543 | | -Warc-bridge-casts-disallowed-in-nonarc | '%0' casts have no effect when not using ARC | 544 | | -Wattributes | unknown __declspec attribute %0 ignored | 545 | | -Wavailability | 'unavailable' availability overrides all other availability information | 546 | | -Wc++11-compat | use of right-shift operator ('') in template argument will require parentheses in C++11 | 547 | | -Wc++11-compat | 'auto' storage class specifier is redundant and incompatible with C++11 | 548 | | -Wc++98-c++11-compat | 'decltype(auto)' type specifier is incompatible with C++ standards before C++1y | 549 | | -Wc++98-compat | range-based for loop is incompatible with C++98 | 550 | | -Wc++98-compat | alias declarations are incompatible with C++98 | 551 | | -Wc++98-compat | in-class initialization of non-static data members is incompatible with C++98 | 552 | | -Wc++98-compat | defaulted function definitions are incompatible with C++98 | 553 | | -Wc++98-compat | rvalue references are incompatible with C++98 | 554 | | -Wc++98-compat | reference qualifiers on functions are incompatible with C++98 | 555 | | -Wc++98-compat | inline namespaces are incompatible with C++98 | 556 | | -Wc++98-compat | generalized initializer lists are incompatible with C++98 | 557 | | -Wc++98-compat | trailing return types are incompatible with C++98 | 558 | | -Wc++98-compat | enumeration types with a fixed underlying type are incompatible with C++98 | 559 | | -Wc++98-compat | alignof expressions are incompatible with C++98 | 560 | | -Wc++98-compat | '%0' keyword is incompatible with C++98 | 561 | | -Wc++98-compat | 'decltype' type specifier is incompatible with C++98 | 562 | | -Wc++98-compat | deleted function definitions are incompatible with C++98 | 563 | | -Wc++98-compat | consecutive right angle brackets are incompatible with C++98 (use '> >') | 564 | | -Wc++98-compat | static_assert declarations are incompatible with C++98 | 565 | | -Wc++98-compat | scoped enumerations are incompatible with C++98 | 566 | | -Wc++98-compat | lambda expressions are incompatible with C++98 | 567 | | -Wc++98-compat | attributes are incompatible with C++98 | 568 | | -Wc++98-compat | 'alignas' is incompatible with C++98 | 569 | | -Wc++98-compat | noexcept specifications are incompatible with C++98 | 570 | | -Wc++98-compat | literal operators are incompatible with C++98 | 571 | | -Wc++98-compat | noexcept expressions are incompatible with C++98 | 572 | | -Wc++98-compat | 'nullptr' is incompatible with C++98 | 573 | | -Wc++98-compat-pedantic | extra '' outside of a function is incompatible with C++98 | 574 | | -Wc++98-compat-pedantic | extern templates are incompatible with C++98 | 575 | | -Wc++98-compat-pedantic | commas at the end of enumerator lists are incompatible with C++98 | 576 | | -Wdangling-else | add explicit braces to avoid dangling else | 577 | | -Wdeprecated | Use of 'long' with '__vector' is deprecated | 578 | | -Wdeprecated-declarations | use of C-style parameters in Objective-C method declarations is deprecated | 579 | | -Wdeprecated-register | 'register' storage class specifier is deprecated | 580 | | -Wduplicate-decl-specifier | duplicate '%0' declaration specifier | 581 | | -Wextra-semi | extra ';' after member function definition | 582 | | -Wextra-tokens | "extra tokens at the end of '#pragma omp %0' are ignored | 583 | | -Wgcc-compat | GCC does not allow %0 attribute in this position on a function definition | 584 | | -Wignored-attributes | attribute %0 ignored, because it is not attached to a declaration | 585 | | -Wmicrosoft-exists | dependent %select{__if_not_exists|__if_exists}0 declarations are ignored | 586 | | -Wmissing-selector-name | %0 used as the name of the previous parameter rather than as part of the selector | 587 | | -Wsemicolon-before-method-body | semicolon before method body is ignored | 588 | | -Wsource-uses-openmp | "unexpected '#pragma omp ...' in program | 589 | | -Wstatic-inline-explicit-instantiation | ignoring '%select{static|inline}0' keyword on explicit template instantiation | 590 | 591 |
-------------------------------------------------------------------------------- /Articles/lock-benchmark.md: -------------------------------------------------------------------------------- 1 | ### 不同加锁方式耗时测试 2 | 3 | 4 | 见过有人写各种锁的耗时比较, 更喜欢相信自己的实验结论. 测一下. 5 | 6 | 7 | 1. 运行加锁和解锁操作一百万次,取平均时间,测试代码: 8 | 9 | ![image](https://raw.githubusercontent.com/JasonWorking/Articles/master/images/lock-demo.png) 10 | 11 | 12 | 模拟器上输出结果: 13 | 14 | ``` 15 | 16 | 2015-09-15 22:53:53.939 test[37282:10665796] NSLock: Avg. Runtime: 63 ns 17 | 2015-09-15 22:53:54.049 test[37282:10665796] @synchronized: Avg. Runtime: 106 ns 18 | 2015-09-15 22:53:54.113 test[37282:10665796] NSCondition: Avg. Runtime: 63 ns 19 | 2015-09-15 22:53:54.277 test[37282:10665796] NSConditionLock: Avg. Runtime: 162 ns 20 | 2015-09-15 22:53:54.342 test[37282:10665796] NSRecursiveLock: Avg. Runtime: 64 ns 21 | 2015-09-15 22:53:54.355 test[37282:10665796] OSSpinLock: Avg. Runtime: 11 ns 22 | 23 | 24 | ``` 25 | 26 | 27 | 28 | iPhone6 plus上输出结果: 29 | 30 | ``` 31 | 32 | 33 | 2015-09-15 22:55:56.865 test[31912:3398258] NSLock: Avg. Runtime: 184 ns 34 | 2015-09-15 22:55:57.161 test[31912:3398258] @synchronized: Avg. Runtime: 291 ns 35 | 2015-09-15 22:55:57.331 test[31912:3398258] NSCondition: Avg. Runtime: 168 ns 36 | 2015-09-15 22:55:57.776 test[31912:3398258] NSConditionLock: Avg. Runtime: 442 ns 37 | 2015-09-15 22:55:57.965 test[31912:3398258] NSRecursiveLock: Avg. Runtime: 186 ns 38 | 2015-09-15 22:55:58.005 test[31912:3398258] OSSpinLock: Avg. Runtime: 38 ns 39 | 40 | 41 | ``` 42 | 43 | 44 | 大致整理一下: 45 | 46 | | 加解锁方式 | 耗时(ns) | 47 | |---|---:| 48 | | NSConditionLock | 442 | 49 | | @synchronized | 291 | 50 | | NSRecursiveLock | 186 | 51 | | NSLock | 184 | 52 | | NSCondition | 168 | 53 | | OSSpinLock | 38 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Articles/viweDidLoad-viewWillAppear-in-one-event-loop.md: -------------------------------------------------------------------------------- 1 | Date: 2015-05-12 2 | Title: 证明UIViewContrller中viewDidLoad和viewWillAppear在runloop的同一次循环中 3 | Published: true 4 | Type: post 5 | 6 | --- 7 | ## 证明UIViewContrller中viewDidLoad和viewWillAppear在同一次`event loop`中(runloop的同一次循环中) 8 | 9 | ### 1 测试环境: 10 | 1. 模拟器iOS7,模拟器iOS8 11 | 12 | ### 2 预备知识: 13 | 1. ARC下方法命名与内存管理之间的关系: 14 | * 若方法名以以下词语开头,其返回的对象归调用者所有. 15 | * alloc 16 | * new 17 | * copy 18 | * mutableCopy 19 | * 若方法名不以上述4个词语开头,且返回后不需要retain操作,即没有strong指针指向返回值,则其返回值是autorelease的.[^1] 20 | 21 | 2. autorelease的对象会加入到autoreleasePool中,每一个runloop循环会drain一次autoreleasePool,对pool中的对象发送release消息。 22 | 23 | 3. 若在viewDidLoad中初始化一个autorelease对象,若在viewWillAppear中该对象仍未释放,则证明二者在同一次event loop 中. 24 | 25 | 26 | ### 测试代码: 27 | 28 | ``` 29 | @implementation ViewController 30 | 31 | __weak id string = nil; 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | 36 | //这里使用的初始化函数如果是 [[NSString alloc]initWithFormat:@"aaa"]; 37 | //则返回的字符串并不是autorelease的,不支持本次测试. 38 | NSString *object = [NSString stringWithFormat:@"aaa"]; 39 | NSLog(@"%@,%s", object,__func__); 40 | string = object; 41 | 42 | } 43 | 44 | - (void)viewWillAppear:(BOOL)animated 45 | { 46 | [super viewWillAppear:animated]; 47 | NSLog(@"%@,%s", string,__func__); 48 | 49 | } 50 | 51 | - (void)viewDidAppear:(BOOL)animated 52 | { 53 | [super viewDidAppear:animated]; 54 | NSLog(@"%@,%s", string,__func__); 55 | } 56 | ``` 57 | 58 | ### 输出结果: 59 | 60 | ``` 61 | 2015-05-12 17:25:48.036 Layout[12135:607] aaa,-[ViewController viewDidLoad] 62 | 2015-05-12 17:25:53.104 Layout[12135:607] aaa,-[ViewController viewWillAppear:] 63 | 2015-05-12 17:25:53.287 Layout[12135:607] (null),-[ViewController viewDidAppear:] 64 | 65 | 66 | ``` 67 | 68 | ### 其他论证: 69 | > 查阅github上一套非官方的开源的[UIKit源码](https://github.com/BigZaphod/Chameleon),看看UIViewController的实现如何: 70 | 71 | ``` 72 | // UIViewController.m 73 | 74 | ... 75 | 76 | - (BOOL)isViewLoaded 77 | { 78 | return (_view != nil); 79 | } 80 | 81 | - (UIView *)view 82 | { 83 | if ([self isViewLoaded]) { 84 | return _view; 85 | } else { 86 | const BOOL wereEnabled = [UIView areAnimationsEnabled]; 87 | [UIView setAnimationsEnabled:NO]; 88 | [self loadView]; 89 | [self viewDidLoad]; 90 | [UIView setAnimationsEnabled:wereEnabled]; 91 | return _view; 92 | } 93 | } 94 | 95 | 96 | 97 | - (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated 98 | { 99 | if (_appearanceTransitionStack == 0 || (_appearanceTransitionStack > 0 && _viewIsAppearing != isAppearing)) { 100 | _appearanceTransitionStack = 1; 101 | _appearanceTransitionIsAnimated = animated; 102 | _viewIsAppearing = isAppearing; 103 | 104 | if ([self shouldAutomaticallyForwardAppearanceMethods]) { 105 | for (UIViewController *child in self.childViewControllers) { 106 | if ([child isViewLoaded] && [child.view isDescendantOfView:self.view]) { 107 | [child beginAppearanceTransition:isAppearing animated:animated]; 108 | } 109 | } 110 | } 111 | 112 | if (_viewIsAppearing) { 113 | 114 | //(view未初始化时,会掉loadView,然后调用viewDidLoad) 115 | [self view]; // ensures the view is loaded before viewWillAppear: happens 116 | [self viewWillAppear:_appearanceTransitionIsAnimated]; 117 | 118 | } else { 119 | [self viewWillDisappear:_appearanceTransitionIsAnimated]; 120 | } 121 | } else { 122 | _appearanceTransitionStack++; 123 | } 124 | } 125 | 126 | 127 | 128 | ``` 129 | > 可以认为其中 - (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated是VC的view lifecycle的开始点[^2]。 130 | > 可以看到在VC.view未初始化时,VC会调用loadView,并调用viewDidLoad,紧接着就会调ViewWillApprear,这两个操作应该是同一个event loop中的. 131 | 132 | 133 | ### 结论: 134 | 135 | ####UIViewContrller中viewDidLoad和viewWillAppear在同一次`event loop`中. 136 | 137 | 138 | 139 | 140 | [^1]: 之所以说“方法名不以上述4个词语开头,`且返回后不需要retain操作,即没有strong指针指向返回值,`则其返回值是autorelease的.”是因为: 对于ARC会使用特殊函数`objc_autoReleaseReturnValue()`来代替简单的`autorelease` 以优化先autorelease再retain这种多余的操作(配合`objc_retainAutoreleaseReturnValue()`). 详情可参见《Effective Object-C 2.0》第30条。 141 | 142 | [^2]: 当ViewController为window.rootViewController时,ViewController的view加到window上时会调用VC的 - (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated; 若VC在一个containnerController下(如NavigationController\tabbarController),则这些containnerController会在add或remove一个子VC时,调用子VC的 - (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated. 143 | 144 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 96B1E2B41B3A7F4A0063F75F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 96B1E2B31B3A7F4A0063F75F /* main.m */; }; 11 | 96B1E2B71B3A7F4A0063F75F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 96B1E2B61B3A7F4A0063F75F /* AppDelegate.m */; }; 12 | 96B1E2BA1B3A7F4A0063F75F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 96B1E2B91B3A7F4A0063F75F /* ViewController.m */; }; 13 | 96B1E2BD1B3A7F4A0063F75F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 96B1E2BB1B3A7F4A0063F75F /* Main.storyboard */; }; 14 | 96B1E2BF1B3A7F4A0063F75F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 96B1E2BE1B3A7F4A0063F75F /* Images.xcassets */; }; 15 | 96B1E2C21B3A7F4A0063F75F /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96B1E2C01B3A7F4A0063F75F /* LaunchScreen.xib */; }; 16 | 96B1E2CE1B3A7F4A0063F75F /* DeallocDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96B1E2CD1B3A7F4A0063F75F /* DeallocDemoTests.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 96B1E2C81B3A7F4A0063F75F /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 96B1E2A61B3A7F4A0063F75F /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 96B1E2AD1B3A7F4A0063F75F; 25 | remoteInfo = DeallocDemo; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 96B1E2AE1B3A7F4A0063F75F /* DeallocDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DeallocDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 96B1E2B21B3A7F4A0063F75F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 96B1E2B31B3A7F4A0063F75F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 96B1E2B51B3A7F4A0063F75F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | 96B1E2B61B3A7F4A0063F75F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | 96B1E2B81B3A7F4A0063F75F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 36 | 96B1E2B91B3A7F4A0063F75F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 37 | 96B1E2BC1B3A7F4A0063F75F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 38 | 96B1E2BE1B3A7F4A0063F75F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 39 | 96B1E2C11B3A7F4A0063F75F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 40 | 96B1E2C71B3A7F4A0063F75F /* DeallocDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DeallocDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 96B1E2CC1B3A7F4A0063F75F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 42 | 96B1E2CD1B3A7F4A0063F75F /* DeallocDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeallocDemoTests.m; sourceTree = ""; }; 43 | /* End PBXFileReference section */ 44 | 45 | /* Begin PBXFrameworksBuildPhase section */ 46 | 96B1E2AB1B3A7F4A0063F75F /* Frameworks */ = { 47 | isa = PBXFrameworksBuildPhase; 48 | buildActionMask = 2147483647; 49 | files = ( 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | 96B1E2C41B3A7F4A0063F75F /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | 96B1E2A51B3A7F4A0063F75F = { 64 | isa = PBXGroup; 65 | children = ( 66 | 96B1E2B01B3A7F4A0063F75F /* DeallocDemo */, 67 | 96B1E2CA1B3A7F4A0063F75F /* DeallocDemoTests */, 68 | 96B1E2AF1B3A7F4A0063F75F /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | 96B1E2AF1B3A7F4A0063F75F /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 96B1E2AE1B3A7F4A0063F75F /* DeallocDemo.app */, 76 | 96B1E2C71B3A7F4A0063F75F /* DeallocDemoTests.xctest */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | 96B1E2B01B3A7F4A0063F75F /* DeallocDemo */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 96B1E2B51B3A7F4A0063F75F /* AppDelegate.h */, 85 | 96B1E2B61B3A7F4A0063F75F /* AppDelegate.m */, 86 | 96B1E2B81B3A7F4A0063F75F /* ViewController.h */, 87 | 96B1E2B91B3A7F4A0063F75F /* ViewController.m */, 88 | 96B1E2BB1B3A7F4A0063F75F /* Main.storyboard */, 89 | 96B1E2BE1B3A7F4A0063F75F /* Images.xcassets */, 90 | 96B1E2C01B3A7F4A0063F75F /* LaunchScreen.xib */, 91 | 96B1E2B11B3A7F4A0063F75F /* Supporting Files */, 92 | ); 93 | path = DeallocDemo; 94 | sourceTree = ""; 95 | }; 96 | 96B1E2B11B3A7F4A0063F75F /* Supporting Files */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 96B1E2B21B3A7F4A0063F75F /* Info.plist */, 100 | 96B1E2B31B3A7F4A0063F75F /* main.m */, 101 | ); 102 | name = "Supporting Files"; 103 | sourceTree = ""; 104 | }; 105 | 96B1E2CA1B3A7F4A0063F75F /* DeallocDemoTests */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 96B1E2CD1B3A7F4A0063F75F /* DeallocDemoTests.m */, 109 | 96B1E2CB1B3A7F4A0063F75F /* Supporting Files */, 110 | ); 111 | path = DeallocDemoTests; 112 | sourceTree = ""; 113 | }; 114 | 96B1E2CB1B3A7F4A0063F75F /* Supporting Files */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 96B1E2CC1B3A7F4A0063F75F /* Info.plist */, 118 | ); 119 | name = "Supporting Files"; 120 | sourceTree = ""; 121 | }; 122 | /* End PBXGroup section */ 123 | 124 | /* Begin PBXNativeTarget section */ 125 | 96B1E2AD1B3A7F4A0063F75F /* DeallocDemo */ = { 126 | isa = PBXNativeTarget; 127 | buildConfigurationList = 96B1E2D11B3A7F4A0063F75F /* Build configuration list for PBXNativeTarget "DeallocDemo" */; 128 | buildPhases = ( 129 | 96B1E2AA1B3A7F4A0063F75F /* Sources */, 130 | 96B1E2AB1B3A7F4A0063F75F /* Frameworks */, 131 | 96B1E2AC1B3A7F4A0063F75F /* Resources */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | ); 137 | name = DeallocDemo; 138 | productName = DeallocDemo; 139 | productReference = 96B1E2AE1B3A7F4A0063F75F /* DeallocDemo.app */; 140 | productType = "com.apple.product-type.application"; 141 | }; 142 | 96B1E2C61B3A7F4A0063F75F /* DeallocDemoTests */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = 96B1E2D41B3A7F4A0063F75F /* Build configuration list for PBXNativeTarget "DeallocDemoTests" */; 145 | buildPhases = ( 146 | 96B1E2C31B3A7F4A0063F75F /* Sources */, 147 | 96B1E2C41B3A7F4A0063F75F /* Frameworks */, 148 | 96B1E2C51B3A7F4A0063F75F /* Resources */, 149 | ); 150 | buildRules = ( 151 | ); 152 | dependencies = ( 153 | 96B1E2C91B3A7F4A0063F75F /* PBXTargetDependency */, 154 | ); 155 | name = DeallocDemoTests; 156 | productName = DeallocDemoTests; 157 | productReference = 96B1E2C71B3A7F4A0063F75F /* DeallocDemoTests.xctest */; 158 | productType = "com.apple.product-type.bundle.unit-test"; 159 | }; 160 | /* End PBXNativeTarget section */ 161 | 162 | /* Begin PBXProject section */ 163 | 96B1E2A61B3A7F4A0063F75F /* Project object */ = { 164 | isa = PBXProject; 165 | attributes = { 166 | LastUpgradeCheck = 0630; 167 | ORGANIZATIONNAME = "Jason Kaer"; 168 | TargetAttributes = { 169 | 96B1E2AD1B3A7F4A0063F75F = { 170 | CreatedOnToolsVersion = 6.3.2; 171 | }; 172 | 96B1E2C61B3A7F4A0063F75F = { 173 | CreatedOnToolsVersion = 6.3.2; 174 | TestTargetID = 96B1E2AD1B3A7F4A0063F75F; 175 | }; 176 | }; 177 | }; 178 | buildConfigurationList = 96B1E2A91B3A7F4A0063F75F /* Build configuration list for PBXProject "DeallocDemo" */; 179 | compatibilityVersion = "Xcode 3.2"; 180 | developmentRegion = English; 181 | hasScannedForEncodings = 0; 182 | knownRegions = ( 183 | en, 184 | Base, 185 | ); 186 | mainGroup = 96B1E2A51B3A7F4A0063F75F; 187 | productRefGroup = 96B1E2AF1B3A7F4A0063F75F /* Products */; 188 | projectDirPath = ""; 189 | projectRoot = ""; 190 | targets = ( 191 | 96B1E2AD1B3A7F4A0063F75F /* DeallocDemo */, 192 | 96B1E2C61B3A7F4A0063F75F /* DeallocDemoTests */, 193 | ); 194 | }; 195 | /* End PBXProject section */ 196 | 197 | /* Begin PBXResourcesBuildPhase section */ 198 | 96B1E2AC1B3A7F4A0063F75F /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | 96B1E2BD1B3A7F4A0063F75F /* Main.storyboard in Resources */, 203 | 96B1E2C21B3A7F4A0063F75F /* LaunchScreen.xib in Resources */, 204 | 96B1E2BF1B3A7F4A0063F75F /* Images.xcassets in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | 96B1E2C51B3A7F4A0063F75F /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | }; 215 | /* End PBXResourcesBuildPhase section */ 216 | 217 | /* Begin PBXSourcesBuildPhase section */ 218 | 96B1E2AA1B3A7F4A0063F75F /* Sources */ = { 219 | isa = PBXSourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 96B1E2BA1B3A7F4A0063F75F /* ViewController.m in Sources */, 223 | 96B1E2B71B3A7F4A0063F75F /* AppDelegate.m in Sources */, 224 | 96B1E2B41B3A7F4A0063F75F /* main.m in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | 96B1E2C31B3A7F4A0063F75F /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | 96B1E2CE1B3A7F4A0063F75F /* DeallocDemoTests.m in Sources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | /* End PBXSourcesBuildPhase section */ 237 | 238 | /* Begin PBXTargetDependency section */ 239 | 96B1E2C91B3A7F4A0063F75F /* PBXTargetDependency */ = { 240 | isa = PBXTargetDependency; 241 | target = 96B1E2AD1B3A7F4A0063F75F /* DeallocDemo */; 242 | targetProxy = 96B1E2C81B3A7F4A0063F75F /* PBXContainerItemProxy */; 243 | }; 244 | /* End PBXTargetDependency section */ 245 | 246 | /* Begin PBXVariantGroup section */ 247 | 96B1E2BB1B3A7F4A0063F75F /* Main.storyboard */ = { 248 | isa = PBXVariantGroup; 249 | children = ( 250 | 96B1E2BC1B3A7F4A0063F75F /* Base */, 251 | ); 252 | name = Main.storyboard; 253 | sourceTree = ""; 254 | }; 255 | 96B1E2C01B3A7F4A0063F75F /* LaunchScreen.xib */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | 96B1E2C11B3A7F4A0063F75F /* Base */, 259 | ); 260 | name = LaunchScreen.xib; 261 | sourceTree = ""; 262 | }; 263 | /* End PBXVariantGroup section */ 264 | 265 | /* Begin XCBuildConfiguration section */ 266 | 96B1E2CF1B3A7F4A0063F75F /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BOOL_CONVERSION = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INT_CONVERSION = YES; 280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 284 | COPY_PHASE_STRIP = NO; 285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 286 | ENABLE_STRICT_OBJC_MSGSEND = YES; 287 | GCC_C_LANGUAGE_STANDARD = gnu99; 288 | GCC_DYNAMIC_NO_PIC = NO; 289 | GCC_NO_COMMON_BLOCKS = YES; 290 | GCC_OPTIMIZATION_LEVEL = 0; 291 | GCC_PREPROCESSOR_DEFINITIONS = ( 292 | "DEBUG=1", 293 | "$(inherited)", 294 | ); 295 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 296 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 297 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 298 | GCC_WARN_UNDECLARED_SELECTOR = YES; 299 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 300 | GCC_WARN_UNUSED_FUNCTION = YES; 301 | GCC_WARN_UNUSED_VARIABLE = YES; 302 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 303 | MTL_ENABLE_DEBUG_INFO = YES; 304 | ONLY_ACTIVE_ARCH = YES; 305 | SDKROOT = iphoneos; 306 | }; 307 | name = Debug; 308 | }; 309 | 96B1E2D01B3A7F4A0063F75F /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ALWAYS_SEARCH_USER_PATHS = NO; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_CONSTANT_CONVERSION = YES; 319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 320 | CLANG_WARN_EMPTY_BODY = YES; 321 | CLANG_WARN_ENUM_CONVERSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_UNREACHABLE_CODE = YES; 325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 326 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 327 | COPY_PHASE_STRIP = NO; 328 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 329 | ENABLE_NS_ASSERTIONS = NO; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | GCC_C_LANGUAGE_STANDARD = gnu99; 332 | GCC_NO_COMMON_BLOCKS = YES; 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 340 | MTL_ENABLE_DEBUG_INFO = NO; 341 | SDKROOT = iphoneos; 342 | VALIDATE_PRODUCT = YES; 343 | }; 344 | name = Release; 345 | }; 346 | 96B1E2D21B3A7F4A0063F75F /* Debug */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 350 | INFOPLIST_FILE = DeallocDemo/Info.plist; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 352 | PRODUCT_NAME = "$(TARGET_NAME)"; 353 | }; 354 | name = Debug; 355 | }; 356 | 96B1E2D31B3A7F4A0063F75F /* Release */ = { 357 | isa = XCBuildConfiguration; 358 | buildSettings = { 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 360 | INFOPLIST_FILE = DeallocDemo/Info.plist; 361 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 362 | PRODUCT_NAME = "$(TARGET_NAME)"; 363 | }; 364 | name = Release; 365 | }; 366 | 96B1E2D51B3A7F4A0063F75F /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | BUNDLE_LOADER = "$(TEST_HOST)"; 370 | FRAMEWORK_SEARCH_PATHS = ( 371 | "$(SDKROOT)/Developer/Library/Frameworks", 372 | "$(inherited)", 373 | ); 374 | GCC_PREPROCESSOR_DEFINITIONS = ( 375 | "DEBUG=1", 376 | "$(inherited)", 377 | ); 378 | INFOPLIST_FILE = DeallocDemoTests/Info.plist; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DeallocDemo.app/DeallocDemo"; 382 | }; 383 | name = Debug; 384 | }; 385 | 96B1E2D61B3A7F4A0063F75F /* Release */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | BUNDLE_LOADER = "$(TEST_HOST)"; 389 | FRAMEWORK_SEARCH_PATHS = ( 390 | "$(SDKROOT)/Developer/Library/Frameworks", 391 | "$(inherited)", 392 | ); 393 | INFOPLIST_FILE = DeallocDemoTests/Info.plist; 394 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 395 | PRODUCT_NAME = "$(TARGET_NAME)"; 396 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DeallocDemo.app/DeallocDemo"; 397 | }; 398 | name = Release; 399 | }; 400 | /* End XCBuildConfiguration section */ 401 | 402 | /* Begin XCConfigurationList section */ 403 | 96B1E2A91B3A7F4A0063F75F /* Build configuration list for PBXProject "DeallocDemo" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | 96B1E2CF1B3A7F4A0063F75F /* Debug */, 407 | 96B1E2D01B3A7F4A0063F75F /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | 96B1E2D11B3A7F4A0063F75F /* Build configuration list for PBXNativeTarget "DeallocDemo" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | 96B1E2D21B3A7F4A0063F75F /* Debug */, 416 | 96B1E2D31B3A7F4A0063F75F /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | }; 420 | 96B1E2D41B3A7F4A0063F75F /* Build configuration list for PBXNativeTarget "DeallocDemoTests" */ = { 421 | isa = XCConfigurationList; 422 | buildConfigurations = ( 423 | 96B1E2D51B3A7F4A0063F75F /* Debug */, 424 | 96B1E2D61B3A7F4A0063F75F /* Release */, 425 | ); 426 | defaultConfigurationIsVisible = 0; 427 | }; 428 | /* End XCConfigurationList section */ 429 | }; 430 | rootObject = 96B1E2A61B3A7F4A0063F75F /* Project object */; 431 | } 432 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DeallocDemo 4 | // 5 | // Created by Jason Kaer on 15/6/24. 6 | // Copyright (c) 2015年 Jason Kaer. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DeallocDemo 4 | // 5 | // Created by Jason Kaer on 15/6/24. 6 | // Copyright (c) 2015年 Jason Kaer. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // DeallocDemo 4 | // 5 | // Created by Jason Kaer on 15/6/24. 6 | // Copyright (c) 2015年 Jason Kaer. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // DeallocDemo 4 | // 5 | // Created by Jason Kaer on 15/6/24. 6 | // Copyright (c) 2015年 Jason Kaer. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ClassFoo : NSObject 12 | @end 13 | 14 | @implementation ClassFoo 15 | 16 | - (void)dealloc 17 | { 18 | NSLog(@"dealloc is excuted in thread : %@, object : %@", [NSThread currentThread], self); 19 | } 20 | 21 | @end 22 | 23 | 24 | 25 | @interface ViewController () 26 | @property (nonatomic, strong) NSMutableArray *array; 27 | @end 28 | 29 | @implementation ViewController 30 | 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | // Do any additional setup after loading the view, typically from a nib. 34 | 35 | _array = [NSMutableArray array]; 36 | ClassFoo *objectFoo = [[ClassFoo alloc] init]; 37 | NSLog(@"Thread: %@, object : %@", [NSThread currentThread],objectFoo); 38 | [_array addObject:objectFoo]; 39 | 40 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 41 | [[NSThread currentThread] setName:@"DISPATCH_QUEUE_Thread_Custom"]; 42 | [_array removeAllObjects]; 43 | }); 44 | 45 | // dispatch_async(dispatch_get_main_queue(), ^{ 46 | // [_array removeAllObjects]; 47 | // }); 48 | 49 | 50 | 51 | } 52 | 53 | 54 | @end 55 | 56 | 57 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DeallocDemo 4 | // 5 | // Created by Jason Kaer on 15/6/24. 6 | // Copyright (c) 2015年 Jason Kaer. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demos/DeallocDemo/DeallocDemoTests/DeallocDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DeallocDemoTests.m 3 | // DeallocDemoTests 4 | // 5 | // Created by Jason Kaer on 15/6/24. 6 | // Copyright (c) 2015年 Jason Kaer. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface DeallocDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation DeallocDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Articles 2 | 3 | ### 目录 4 | 5 | #### UIKit 6 | --- 7 | 1. [UIView中layoutSubviews何时会被调用](https://github.com/JasonWorking/Articles/blob/master/Articles/When-layoutsubviews-get-called.md) 8 | 9 | 2. [证明UIViewController的ViewDidLoad和ViewWillAppear在同一个Event loop中](https://github.com/JasonWorking/Articles/blob/master/Articles/viweDidLoad-viewWillAppear-in-one-event-loop.md) 10 | 11 | 3. [子View在父view的外部时的点击事件处理实例.](https://github.com/JasonWorking/Articles/blob/master/Articles/Touch-events-outside.md) 12 | 13 | 4. [实现自定义UINavigationController的转场动画(iOS6+)](https://github.com/JasonWorking/GTNavigationController) 14 | 15 | 16 | #### Foundation 17 | --- 18 | 1. [NSDictionary类簇实现](https://github.com/JasonWorking/Articles/blob/master/Articles/Class-Cluster-NSDictionary.md) 19 | 20 | 2. 实现弱引用的NSArray/NSMutableArray(non-retaining NSArry/NSMutableArray) 21 | 22 | 23 | 24 | #### 内存管理、多线程 25 | --- 26 | 1. [dealloc在哪个线程执行](https://github.com/JasonWorking/Articles/blob/master/Articles/Dealloc.md) 27 | 28 | 2. NSNotification跨线程发送和接收通知. 29 | 30 | 3. AutoreleasePool 与 runloop . 31 | 32 | 4. [不同加锁方式耗时比较. ](https://github.com/JasonWorking/Articles/blob/master/Articles/lock-benchmark.md) 33 | 34 | 35 | #### Runtime 36 | --- 37 | 1. OC runtime 的消息转发机制 38 | 2. Method Swizzling的使用方法,并用其解决几个常见问题. 39 | 3. [使用Method Swizzling的弊端](https://github.com/JasonWorking/Articles/blob/master/Articles/Danger%20of%20Method%20Swizzling.md) 40 | 4. 深入理解category 41 | 5. Associated object 实现原理 42 | 43 | #### Tools 44 | --- 45 | 46 | 1. [PhonyDebugger的正确安装姿势](https://github.com/JasonWorking/Articles/blob/master/Articles/Install-PhonyDebugger.md) 47 | 2. UI调试神器: Reveal安装和使用 48 | 3. 网络抓包: Charles 49 | 4. iConsole 50 | 5. Log: CocoaLumberjack 51 | 6. lldb: Chisel 52 | 7. 代码绘制图形: PaintCode 53 | 8. CodeInventor 54 | 55 | #### CrashLog,App安全 56 | --- 57 | 1. Crash日志分析 58 | 59 | 2. Crash日志的收集原理以及QuincyKit简介 60 | 61 | 3. iOS应用安全中的常见破解手段 62 | 63 | 4. iOS应用安全加固: 检测Debugger 64 | 65 | 5. 阻止GDB依附时,ptrace被苹果审核报私有API调用的解决办法 66 | 67 | #### 架构 68 | --- 69 | 1. UITableView的dataSource和Delegate的统一处理(解决Massive ViewController问题) 70 | 71 | 2. 使用MVC框架的正确姿势,以及MVVM、VIPER框架简介 72 | 73 | 74 | #### Hybrid/ Semi-hybrid 75 | --- 76 | 1. BeeFramework 77 | 2. Samurai 78 | 3. React Native 79 | 80 | 81 | #### 开源库源码 82 | --- 83 | 1. AFNetworking源码解析 84 | 85 | 2. SDWebImage源码解析 86 | 87 | 3. BeeFramework 源码解析 88 | 89 | 4. fishhook 90 | 91 | 92 | #### 奇技淫巧 93 | --- 94 | 1. GPX文件 95 | 2. [CGRect、CGPoint等的写法](https://github.com/JasonWorking/Articles/blob/master/Articles/CGSize-CGPoint.md) 96 | 3. [不需要复用的代码块](https://github.com/JasonWorking/Articles/blob/master/Articles/Little-code-block.md) 97 | 4. [Fucking clang warning](https://github.com/JasonWorking/Articles/blob/master/Articles/fucking-clang-warnings.md) 98 | 5. [常用lldb、Xcode调试Tips](https://github.com/JasonWorking/Articles/blob/master/Articles/common-debug-tips.md) 99 | 6. 分享SDK是如何实现的 100 | 101 | #### C/C++,算法,数据结构等 102 | --- 103 | 104 | 1. [常见字符编码方式的由来](https://github.com/JasonWorking/Articles/blob/master/Articles/ASCII-Unicode-UTF8.md) 105 | 2. 《程序员的自我修养》- 编译、链接 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /images/connected.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/connected.jpg -------------------------------------------------------------------------------- /images/hit-testing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/hit-testing.jpg -------------------------------------------------------------------------------- /images/inside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/inside.jpg -------------------------------------------------------------------------------- /images/lldb-demo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/lldb-demo-1.png -------------------------------------------------------------------------------- /images/localhost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/localhost.png -------------------------------------------------------------------------------- /images/lock-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/lock-demo.png -------------------------------------------------------------------------------- /images/symbolic-breakpoint-demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/symbolic-breakpoint-demo.jpg -------------------------------------------------------------------------------- /images/xode-debug-demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonWorking/Articles/b0a0b75a63d69258c12f7fcdd96527b25cdc1480/images/xode-debug-demo1.jpg --------------------------------------------------------------------------------