1、关于SEL类型的数据:
(1)、SEL类型的数据包含的是一个方法,使用@selector()把一个方法名包含在括号内,就可以取到这个方法,然后可以以这个数据作为参数去调用一些方法;
(2)、一般用于那些处理动态类型的方法中,比如有方法-(BOOL)respondToSelector: selector,这个方法是判断某个类能否响应某个方法。比如有实例a,有方法b,这个方法的应用如下:
[a respondToSelector: @selector(b)];
当然它的返回值是BOOL类型,需要用来做判断,这里不做演示。这个例子可以说明@selector是怎么使用的;
(3)、对于放在@selector括号里面的方法名后面的分号:如果方法没有参数,那么括号里不能写上分号,比如:@selector(b),如果方法有参数,则全部分号都必须写上,比如:@selector(add:and:)或者:@selector(b:);
(4)、对于所有的类,只要方法名是一样的,产生的selector都是一样的。
2、使不同的类共享相同的方法名称的能力成为多态。假如Fraction类和Complex类都包含了add:方法,并且分别有实例f1、f2、f3、c1、c2、c3,那么当执行以下语句的时候:
f1 = [f2 add: f2];
c1 = [c2 add: c3];
编译器会自动匹配Fraction类和Complex类各自的add:方法,这就是多态。
3、id类型是一种通用的对象类型,可以用来存储任何类的对象。同时需要注意,在声明类的实例的时候是要用到“*”号的(比如“Fraction *f1;”),而声明一个id类型的对象时,不需要用到“*”号(比如“id dataValue;”)。
4、关于动态绑定:在编译的时候无法确定对象的类型,直到在运行的时候才能确定,进而确定要调用的方法。比如使用id类型定义一个对象,然后使用这个对象调用方法,那么编译的时候编译器无法确定这个对象的类型,直到运行的时候才能正确匹配。
5、动态绑定也会带来一些问题,比如A类不包含方法b:,那么以下语句:
…
id a = [[A alloc] init];
[a b];
…
编译器无法检查出错误,因为在动态绑定之前,编译器并不知道a的类型,所以也无法判断a使用b:方法是否正确。
6、id变量不能使用点运算符,编译器会报错。
7、编译器在编译的时候不会检查id类型的具体类型的!
8、当使用动态类型的对象作为参数来调用方法的时候,如果调用了不同的类相同名称的方法,必须保证:每个方法需求的参数类型和返回值类型必须匹配。即是动态类型的对象在运行时被赋予了确定的类型时,这个类型必须能够匹配代码中调用的方法所需要的类型。比如dataValue1和dataValue2是id类型,有如下代码:
result = [dataValue1 add: dataValue2];
那么编译器仍然会生成代码,它是通过假设来处理返回值的。这时候如果在运行时dataValue1和dataValue2被赋予的类型和add:方法不匹配,那么就会出现错误。
9、关于对象的静态类型和动态类型:
静态类型的对象即是对对象的类型已经进行过显式声明的,比如“Fraction *f1;”,它的类型是确定的、不变的、静态的;动态类型的对象即是对象的类型并未在一开始就确定(但是可能会先有声明),比如“id f1;”,它的类型是未定的、可变的、动态的。
10、类名并不等同于类,比如在程序中,Fraction这个名字并不等同于Fraction类,如果需要使用到Fraction的类,需要使用以下代码:
[Fraction class];
那么就能取到Fraction的类。这种做法的作用是,有时可以做如下判断:
if ([a clsaa] == [b class])
可以知道a和b是不是属于同一个类;
11、关于@try块处理异常,一般的处理模板如下:
…
@try {
[f noSuchMethod];
}
@catch (NSException *exception) {
…
}
…
12、另外如果出现@finally块的话,无论@try块内是否会抛出异常,@finally块都会执行。