1、NSObject访问子类方法
NSObject是所有类的基类,可以指向任何子类
例如:
- #import <Foundation/Foundation.h>
- #pragma mark Animal类声明部分
- @interface Animal: NSObject
- -(void)eat;
- @end
- #pragma mark Animal类实现部分
- @implementation Animal
- -(void)eat{
- NSLog(@"Animal eat...");
- }
- @end
- #pragma mark Dog类声明部分
- @interface Dog: Animal
- -(void)eat;
- @end
- #pragma mark Dog类实现部分
- @implementation Dog
- -(void)eat{
- NSLog(@"Dog eat...");
- }
- @end
-
- int main(int argc, const char * argv[])
- {
-
- @autoreleasepool {
- NSObject *obj = [Animal new];
- NSObject *obj2 = [Dog new];
-
- Animal *ani =[Dog new];
- [ani eat];
- //访问子类特有的方法
- [(Animal*)obj eat];
- [(Dog*)obj2 eat];
-
- }
- return 0;
- }
复制代码
打印结果:
2015-10-05 10:36:57.614 Demo01[1278:303] Dog eat...
2015-10-05 10:36:57.616 Demo01[1278:303] Animal eat...
2015-10-05 10:36:57.617 Demo01[1278:303] Dog eat...
2、id是一种通用的对象类型,它可以用于存储属于任何类的对象
它也可以理解为【万能指针】
【注意】id在定义的时候已经包含了“*”,id指针只能访问os的对象
id类型的定义:
typedef struct objc object{
Class *isa;
}id;
例如:
- //id类型使用
- id dog = obj2;
- id animal = obj;
- //id类型使用时不会有类型检查,编译器在遇到id后就认为它是动态类型,就不会检查它的类型
- [dog eat];//狗在跑
- [animal eat];//动物在吃
复制代码
打印结果:
2015-10-05 10:43:32.727 Demo01[1338:303] Dog eat...
2015-10-05 10:43:32.727 Demo01[1338:303] Animal eat...
3、id和instancetype的异同
ios5之后推出了instancetype类型
1)相同点
都可以作为方法的返回类型
2)不同点
A、instancetype可以返回方法所在类相同类型的对象,id只能返回未知类型的对象。
B、instancetype只能作为返回值,不能像id那样作为参数
FROM: http://bbs.itheima.com/thread-247063-1-1.html
动态数据类型id:
数据类型常用的有:
1.int整型;
2.double双精度型;
3.float单精度型;
4.char字符类型;
等......
数据类型的用途是什么呢?
在计算机语言中,数据类型有三种用途,
1.定义变量;
2.作为函数的参数;
3.作为函数的返回值.
默认情况下,所有的数据类型都是静态数据类型.
默认数据类型的特点如下:
在编译时就知道变量的类型,知道变量中有哪些属性和方法,在编译的时候就可以访问这些属性和方法,并且如果通过静态数据类型定义变量,如果访问了不属于静态数据类型的属性和方法,那么编译器就会报错;
id也是一种数据类型,并且是一种动态数据类型,那么id和其他数据类型一样,也有同样的作用;
动态数据类型的特点:
在编译的时候编译器并不知道变量的真实类型,只有在运行的时候才知道真实的数据类型,并且如果通过动态数据类型定义变量,如果访问了不属于动态数据类型的属性和方法,编译器不会报错.
在多态中,通过静态数据类型定义变量,不能调用子类特有的方法;
Animal * dog = [[Dog alloc]init];//使用父类接收子类的实例对象;
Dog * dd = (Dog *)dog;//强制转换为子类类型
[dd kanMen];//只有强制转换后才能调用子类特有的方法
在多态中,通过动态数据类型定义变量,可以调用子类特有的方法;
id dog = [[Dog alloc]init];//创建一条狗;
[dog kanMen];//这条狗可以直接调用Dog类具有的特有方法;
[dog test];//这条狗还可以调用Dog私有的方法//只有实现没有生命的方法是私有方法;
在多态中,通过动态数据类型定义的变量,可以调用私有的方法
Animal * dog = [[Dog alloc]init];//使用父类接收子类的实例对象;
Dog * dd = (Dog *)dog;//强制转换为子类类型
[dd test];//不能调用子类的私有方法
在多态中,如果父类有私有方法,只能在本类的方法中调用,如果子类中有父类私有方法的方法声明,则子类的对象可以直接调用父类的私有方法;(说明,OC中没有真正的私有方法,通过某种途径,父类也是可以调用其私有方法.)
id也存在弊端,由于动态数据类型可以调用任意方法, 所以有可能调用到不属于自己的方法, 而编译时又不会报错, 所以可能导致运行时的错误;
为了避免动态数据类型引发的运行时的错误, 一般情况下如果使用动态数据类型定义一个变量, 在调用这个变量的方法之前会进行一次判断, 判断当前变量是否能够调用这个方法;
if ([dog isKindOfClass:[Dog class]]) {
//isKindOfClass , 判断指定的对象是否是某一个类, 或者是某一个类的子类
[dog eat];
}
//-------------------------------------------------------------------------------------------------------------
if ([dog isMemberOfClass:[Dog class]]) {
// isMemberOfClass : 判断指定的对象是否是当前指定的类的实例
[dog eat];
}
id的应用场景: 多态, 可以减少代码量, 避免调用子类特有的方法需要强制类型转换
注释:
多态的条件:
1.有继承关系
2.父类指向子类
3.子类重写父类方法;
#import <Foundation/Foundation.h>
@interface Animal : NSObject
-(void)eat;
@implementation Animal
-(void)eat
{
NSLog(@"吃饭");
}
-(void)test2
{
NSLog(@"Animal私有方法test2");
}
@end
//———————————————————————//
@interface Dog : Animal
-(void)eat;
-(void)kanMen;
-(void)test2;
@end
@implementation Dog
-(void)eat
{
NSLog(@"dog吃肉");
}
-(void)kanMen
{
NSLog(@"汪汪叫");
}
-(void)test
{
NSLog(@"私有方法test");
}
@end
//——————————————————————//
@interface Person : NSObject
-(void)eat:(Animal*)an;
@end
@implementation Person
-(void)eat:(Animal *)an
{
[an eat];
}
@end
//———————————————————————//
int main(int argc, const char * argv[]) {
// Animal *dog = [[Dog alloc]init];
// [dog eat];
//多态情况下,如果需要调用子类的特有属性,需要强制装换为子类类型
// Animal * dog = [[Dog alloc]init];
// Dog * dd = (Dog *)dog;
// [dd kanMen];
// [dd test];
//使用id类型,在调用子类特有方法的时候,不用再强制转换,可以直接调用;
//使用id类型,可以调用子类的私有方法;
id dog = [[Dog alloc]init];
// [dog kanMen];
// [dog test];
[dog test2];//
// 为了避免动态数据类型引发的运行时的错误, 一般情况下如果使用动态数据类型定义一个变量, 在调用这个变量的方法之前会进行一次判断, 判断当前变量是否能够调用这个方法
// id dog2 = [[Dog alloc]init];
// if ([dog2 isMemberOfClass:[Dog class]] ) {
// [dog2 eat];
// }
//
// Animal * an = [[Animal alloc]init];
// Dog * dog = [[Dog alloc]init];
// Person * p = [[Person alloc]init];
// [p eat:dog];
//真正意义的面向对象;只剩下具体的对象,
//这里是又创建了一个人,和分别创建了一条狗和一只猫,然后就是人去喂猫和狗;
return 0;
}
from: http://blog.csdn.net/batac_lee/article/details/50576314