-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstart.ios.txt
359 lines (202 loc) · 20.3 KB
/
start.ios.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
id obj;
消息表达式 :[obj msg]// obj 接收者 msg 消息
可作为变量嵌套在语句中,或单独执行返回void
允许嵌套
例:element=table[[obj count]]//内层【】 为消息表达式修饰符,外层为数组修饰符,使用【obj count】 的结果作为table[] 数组的下标
msg位置的参数被称为消息关键字,其末尾有“:”时,表示消息带有参数,“:”后紧跟着的就是实参,可以是变量,也可以是消息表达式
例:[doc isSameDirectory:[info objectAtIndex:++num]];
多参消息:
[方法名 关键字1:a 关键字2:b 关键字3:c] 或 [方法名:a:b:c]
例:[ manager fixExistsAtPath:dirname isDirectoty:&isdir]; 或[view lineTo:1.1:(y+1.0)];
消息选择器:消息名(选择器,方法)(对应消息表达式中msg位置?)(函数名?参数名?cell=[albumview cellAtRow:i column:j];)
带有参数的消息选择器要包含“:”
例:copy 和copy:是两个不同的选择器
多参情况:cellAtRow: column:
由多个消息关键字组成的选择器,关键字的顺序不能错,否则是完全不同的选择器
变量:
同C一样,仅声明不会为变量赋初值
OC通过向类发送消息来创建一个对象
例:[类名 alloc]//alloc执行完同C一样为申请到存储空间,仍需调用初始化方法
Cocoa中的初始化方法通常为init或由init开头的函数。
例:[[类名 alloc] init] //完整地创建并初始化Cocoa中的某个类//通常嵌套调用alloc和init来生成一个对象
tip:对象生成后知需调用一次初始化方法,init并没有reset功能,使变量的值恢复初始值需要专用函数,另外,有的类不是用alloc方法而使用其他方法生成对象,
有的类也可能会返回一个初始化好的对象(OC中哪个系的类会?还是在自己实现中灵活运用?)
类的定义:(interface和implementat是分开的)(OC中的类由接口和实现组成?)
语法:
@interface 类名:父类名
{
实例变量的定义;
}
方法声明;
@end
OC中类接口的声明以@interface开头,以@end结尾,所有的OC编译指令都以@ 开头,以区分C中的字符串(关键字?)
方法声明:
-(id)delegate; // "-"表示是实例方法,返回值使用“()”括起来
-(id)cellAtRow:(int)row column:(int) col;//参数的类型指定用“()”括起来放在参数之前,row和col是参数
-(void)setAutoPlay(BOOL)falg;//无返回值时使用void表示
返回值:
可以省略方法返回值,编译器默认增加id类型的返回值(不推荐,不清晰)
tips:在C中省略返回值会默认增加int类型的返回值,但存在争议,有可以能以后会被废除
静态变量:
在函数或类方法范围外定义的变量,及制定了static的变量,生命周期为从程序开始执行到结束。
根类:
NSObject是Cocoa环境下的根类(NSProxy听说也是,Objective-C编程全解,19章)
继承:
实例变量:只需要声明新增的变量,若没有,加上“{}”即可,有时“{}”都可以省略
方法:追加新增的方法,若要重写,则需要在接口中对方法重新声明。
使用super关键字可以实现调用父类中的方法,即使这个方法在子类中已经被重写了
super和self不同, 并不确定指向某个对象,所以只能用于调用父类的方法,不能通过super完成赋值,也不能指定返回值类型为super
初始化:
固定写法:
-(id)init{
self=[super init];//一定在第一行调用父类的init方法
if(self!=nil){//判断父类方法是否调用成功(是有可能失败的),除非父类是NSObject,基本上不可能出错(内存不足呢 ?也不会出错吗?)
}
return self;
}
初始化失败原因:使用传入的参数,或通过从文件读入变量进行初始化,因为值的类型错误或读取文件失败等原因。
生成实例对象的方法alloc会把实例对象的变量都初始化为0(除了实例变量isa),所以若子类中心追加的实例变量的初值可以为0,则可以跳过子类的初始化(父类中不行?),
为了明确是否可省略,最好为初值可以为0的变量加上注释。
原则上说,初始赋值之后值不再变化的变量和需要显示设定初值的变量,都需要通过带参数的初始化方法来进行初始化。
使用self调用方法:
在一个方法中调用当前类中定义的方法,可以利用self,但如果存在继承关系,则需要注意,到底哪个方法被调用了(我的self还是我的self),
self指的是收到当前消息的实例变量,利用self的特性编程很常见。(Objextive-C编程全解,P39)
不要在访问方法中使用self,否则会造成无限循环递归,无法终止
使用super调用方法:《Objective-C编程全解 P41》
super的方法和self完全不同,需要写demo测试,super指的是第一次被继承方法的类的super类?(写4代继承,及隔代继承的demo测试,最好能跟java一起测试)
局部方法:
可以只在实现部分中实现,不需要在接口部分中定义,其他模块引用了这个接口文件也无法获得这个方法的定义,一般为一段具备独立功能的方法。
通常指供内部调用,所以不包含在类的接口中对外公开,但是方法本身还算存在,只要发送了消息,就能够执行。
只能被定义在局部方法之后的方法调用。
使用局部方法可以增强程序的可维护性,但在继承的时候可能会出现问题,苹果公司建议为局部方法名添加固定前缀以解决
例:子类可能会追加一个父类已经实现的局部方法。
指定初始化方法:
确保所有势力变量都能被初始化的方法,是初始化的核心
子类的指定初始化方法必须调用父类的指定初始化方法
如果子类要重写父类中的指定初始化方法,就一定要调用父类的指定初始化方法,而不是调用父类的非指定初始化方法,因为非指定初始化方法内部会调用指定初始化方法,
造成递归调用。
OC中没有特殊语法或关键字来标示指定初始化方法,通常通过注释或文档说明,Cocoa API文档中绝大多数类表明了那个方法是指定初始化方法
非指定初始化方法:
通过封装类调用指定初始化方法的方法
动态绑定:
在程序执行时才确定对象的属性和需相应的消息
C语言中只能通过函数指针模拟,但并不优雅,很麻烦
静态类型:
确定的类型,编译时会进行类型检查;id这种通用类型就不会,id类型结合多态可以是程序更灵活,但编译器不会对id类型进行类型检查,使程序更容易出错。
静态类型除了类型检查,也会在编译时检查接受者是否可以响应收到的消息(方法检查)。
如果仅适用父类中定义的功能,则变量的类型声明为父类也没有问题,此时无法调用子类(真正实例化的对象)的方法,但可以使用强转后再使用子类的方法。
如果把父类的实例对象强转成子类,则不会报错,但是强转语句不生效。
编译时类型检查要点:《Objective-C 编程全解》P53
OC中的多态比java中更丰富(没有继承关系的多态),具体看P54开头
签名:
消息选择器和参数和返回值的类型的信息结合起来构成签名,用于在运行时标记一个方法,
接口文件中方法的定义也叫做签名。
方法签名:
Cocoa提供了类NSMethodSignature,以面向对象的方式记录方法的参数个数,类型,返回值等信息,这个类的实例也叫做方法签名。
OC选择器相同的消息,参数和返回值的类型也应该是相同的(java中参数不同即为多态,返回值也可以不同),由其是有继承关系的情况。(P55)
实际上,Foundation和Application框架内也存在一些选择器相同但签名不同的方法,所以在这一点不要过于追求完美。
编译时发现签名不一致的情况会发出警告,也可以改方法类型为静态类型来屏蔽警告。
(那么OC中的多态怎么实现的?继承,覆写,和没有继承关系的同名方法?)
tips:OC是动态语言,参数的类型是在运行时确定的,不支持根据参数类型不同调用不同函数的重载。
可以通过动态绑定让同一个消息选择器执行不同的功能实现重载(什么是动态绑定?)
前置声明:
在定义一个类的时候,需要使用其他数据类型,又不想引入目标类的头文件,(因为可能目标类中又有引入其他类,会加大编译时负担),此时可使用前置声明。
仅在定义时使用一下类名(若要引用目标文件的具体成员或方法,则必须引入头文件):
使用 @class 告知编译器这是个类名,这种写法被叫做类的前置声明。
class 指令后可一次接多个类,使用“,”分割,使用“;”标示结束,前置声明可以多次声明。
使用 @class可在只使用类名的情况下提高程序整体的编译速度;
当出现多个接口出现类的嵌套定义时,如果只是包含对方的头文件,无法解决,则只能通过类的前置声明来解决。
实例变量的访问权限:
OC 不允许从外部直接访问和修改实例对象的属性,而仅仅可以访问同一个类的其他实例对象的变量,通常会定义专门的方法阿里访问或修改实例变量。
OC 原则上不允许从对象外直接访问对象的实例变量,但类A的方法中可以直接访问类A中包含self以外的其他实例的实例变量。(虽然原则上不允许,但是能做到??)
能不能访问对象的实例变量也需要检查,在编译时完成,因此,只能访问使用静态类型定义的实例对象的内部变量。(???)
对象内外主要指类型?《Objective-C 编程全解》P59有例子,可以明白(看起来就是当前类中可以使用->直接访问其他对象(但是就是当前类的类型(父类也不行))
的内部实例变量(对象也必须使用当前类型声明,id类型不行))
getter和setter:
OC中使用属性名作为getter方法的方法名,setter方法有一个void的返回值
为了封装性更好,降低耦合,即使父子类也应使用这种方法
实例变量的可见性(权限修饰符):
@private,@protected,@public,@package;具体区别见《Objective-c 编程全解》 P61
接口定义中,可以分别为每个实例变量指定访问权限,也可以一次性为一组变量指定访问权限,此时前一个声明到下一个声明(或声明结束)之间的定义的全部变量
都属于该声明的权限,访问权限声明的顺序和次数都没有限制
在Xcode4.2之后允许在实现部分中定义类的实例变量,默认实现部分定义的实例变量权限为@private,可以使用权限修饰符更改权限。(接口文件中省略后默认的实例变量权限是什么????)
这种定义方式有更好的封装性,因为即使追加定义实例变量,也不需要修改接口文件,但子类就无法访问这些实例变量了(可以使用@property)
如果有一个新类定义在了同一个文件中,新类的方法可以访问可见性为@public的实例变量。(??)
类对象:(类方法和实例方法搞不清了?????????????????????????????????????)
OC 中只有类方法的概念,没有类变量的概念,类对象也被称为factory,类方法称为factory method
类方法的一个典型操作就算创建类的实例对象。例如:通过给类名发送alloc消息生成类实例,此处真正调用的是类方法
类对象在程序执行时自动生成,每个类只有一个类对象, 不需要手动生成。alloc方法定义在NSObject中
也可以通过为类对象定义新的方法来完成实例变量的生成和初始化,每个类的所有实例对象都可以使用类方法,类方法可以访问类对象管理的变量(?)
所有的类对象都是Class类型,Class和id一样都是指针类型,Nil被用来表示空指针(是Class而不是对象),实际值是0
将类名定义为消息接收者是类对象特有的功能,除此之外类名只能用在类型定义时。《Objective-c编程全解》P64
实例方法在接口声明和实现文件中以“-”开头,类方法则以“+”开头。
子类可以访问父类的类方法
类方法不能访问类中定义的实例变量和实例方法,类方法中也不能访问实例方法(类的实例对象可以有很多个,类对象只有一个,会搞不清访问按个实例对象)
类方法在执行时使用self代表了类对象自身,因此可以通过给self发送消息的方式来调用类中的其他类方法。(也要注意self的实际指向类)
类变量:
OC 通过在实现文件中定义静态变量的方法来代替类变量。
C 语言的函数和在函数外部定义的变量是全局变量,作用域是整个源程序,程序中任何地方都可以使用这些函数和变量。
加上 static 修饰符后,作用域变为只在其所在的文件内有效,其他文件则不能使用,通常用来定义一些不想对外公开的函数和变量
OC 在实现文件中定义静态变量后,只有类方法和实例方法可也访问这个变量,子类访问则需要定义类方法setter和getter
类变量原则上只在类内部使用。
类对象的初始化:
实例对象的初始化一般分为两步:通过给类对象发送alloc信息为实例对象申请内存,然后通过init对内存进行初始化,即对实例对象的成员变量赋初值
类对象在程序执行的时候已经生成了,需要NSObject中定义的initialze类方法对各类对象进行初始化
在每个类接收到消息之前,为这个类调用一次initialize方法,调用之前会自动调用父类的initialize方法,所以
子类的initialize方法中不必显示调用父类的initialzei方法
每个类的initialize方法只被调用一次,但如果一个类中没有实现initialize方法,其父类的initialize反复就会被调用两次,面向自己一次,面向子类一次,
所以实现initialize方法是哟啊确保该方法能被重复调用
initialize方法非必须,如果没有需要被初始化的变量,则只需对类对象发送一个self消息即可,self定义在NSObiect中,只返回消息接受者本身,没有多余的动作
初始化方法的返回值:
初始化方法的返回值都应该设置为 id 类型,否则子类调用这个方法时返回的就是父类的对象,在继承存在的情况下,尽可以能避免使用静态类型吧代码写死
例:[[Volume alloc] initWithMin:a max:b step:s] 不如写法[[[self class ] alloc] initWithMin:a max:b step:s]
class 是类方法,返回所属的类对象,这样子类也可以原封不动的使用这行代码
引用计数:
Cocoa环境的 OC 提供的一种动态的内存管理方式,基于这种内存管理方式称为基于引用计数的内存管理(MRC或MRR)
内存管理:
1、手动引用计数(手动管理内存)
2、自动引用计数(ARC)
3、垃圾回收(IOS不支持)
程序员可以从手动引用计数管理,ARC和垃圾回收中任意选择一种内存管理放松来开发程序
强烈建议ARC
几个关键字:
alloc 创建一个对象时,该对象的引用计数初始值为1
dealloc 引用计数到达0 时OC 会自动向对象发送一条dealloc来释放内存,通常不允许在程序中直接调用dealloc,
实例方法
retain(保持) 引用计数加 1,返回接收消息的对象(类A在某些过程中使用了实例B,防止B被别的对象随意释放,类A会给实例B发送一个retain)
实例方法
release 引用计数减 1
实例方法
所有权:生成对象或通过给对象发送retain 消息来保持对象这种状态,都可以说拥有这个对象的所有权
是个虚拟概念,无法通过语法标记,程序运行时没法确认某个对象的所有者是谁,方便人们分析阅读时,说明独享之间关系而加的一个属性
所有者:拥有实例对象所有权的对象
释放一个类的实例对象的时候,为了彻底释放该实例对象所保持的所有对象的所有权,需要重写dealloc方法,在其中释放已经分配的资源,
放弃实例变量的所有权,并在末尾调用[super.dealloc]释放父类中定义的实例变量
OC 不允许在栈上分配内存
自动释放:《Objective-C 编程全解》P76
多用于很多使用一次就不再使用的对象
某些需要长时间运行的代码段,或大量使用临时对象的代码段可以通过定义临时的自动释放池来提高内存的利用率(例如一个大量使用临时变量的循环中,经常会在循环开始时
创建自己的自动释放池,在循环结束时释放这个自动释放池,需要注意的是循环中如果通过 break 或者 continue 跳出循环则可能导致自动释放池本身没有被释放掉)
可以给实例对象发送多次retain和autolease消息,同一个对象呗重复登记到自动释放池中,只要autorelease和retain被成对发现就可以
当向一个对象发送autolease时,将该对象添加到NSAutoreleasePool中,将它标记为以后释放,此时此对象还没有被释放,可以继续使用,对象引用计数的值也没有发生变化,
但也相当于放弃了对象所有权,当自动释放池被销毁时,池中记录的所有对象就会被发送release消息。
方法定义:-(id)autorelease
返回值其实是接收消息的对象
典型用法:
id pool =[[NSAutoreleasePool alloc] init];
/*
其他操作
*/
[pool release]//自动释放池销毁,其中所有对象也被销毁
autorelease虽然是NSObject类的方法,但必须和NAAutorelasePool一起使用,自动释放池中不存在对象时,不可以给对象发送autorelease消息,否则会出现运行时错误
临时对象:
生成的对象都是临时对象,生成之后会被直接加入到内部的自动释放池,不需要关心如何销毁它
命名规则是,不以init开头,而以要生成的对象的类型作为开头,同综合使用alloc、init创建对象的方法相比,其所有者不是调用类方法的对象(因为直接被加到自动销毁池了)
这种生成临时对象的类方法,在OC中称为便利构造函数 或便利构造器P78
Cocoa在程序开始时间处理之前会隐式创建一个自动释放池,并在时间处理解释后销毁该自动释放池,所以程序员在进行Cocoa的GUI编程时,不手动创建自动释放池,
也可以使用临时对象
常量对象:
常量对象的生成和释放和一般对象不同,有时需要重写retain和release方法的实现,而ARC和垃圾回收中无法重写这些方法,所以从兼容角度看,不推荐重写这两个方法
给这些对象发送retainCount消息后返回的是NSUIntegerMax(0xffffffff,最大无符号整数,赋值给有符号数,则值为-1)
单例模式:
通过以shared开头的类方法返回唯一的实例对象