1、id语法
可以认为id == NSObject *,运行的环境理解为多态,父类指针指向子类对象,万能指针,能指向\操作任何OC对象。
2、构造方法
构造方法可分为:重写系统自带的构造方法,自定义构造方法。完整地创建一个可用的对象需要下面两步:
1.分配存储空间 +alloc方法 返回一个已经有存储空间的对象,但是这个对象不可用,因为还没有初始化
2.初始化 调用上面分配好存储空间的对象的初始化方法-init
new方法完成这两步,是new方法内部分别调用两个方法完成这两步。分别是+alloc和-init方法
什么是构造方法呢?就相当于init,因为构造方法就一个用途,就是初始化。init默认初始化都为0,如果想让创建的对象初始化为其他值,就要重写父类的init初始化方法。
构造方法:用来初始化对象的方法,是个对象方法,-开头
重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
重写构造方法的注意点:
1.先调用父类的构造方法([super init])
2.再进行子类内部成员变量的初始化
重写-init方法,重写父类方法不用在头文件.h文件中,再次声明,因为在父类中已经声明了。返回类型用id,因为各种对象类型的都需要初始化,所以用id这个文能指针,可以指向任何对象类型,那么各种类型对象就可以赋值给id类型的变量了。
自定义构造方法,就要声明和实现两步,重写父类构造方法,只要实现即可,因为父类中已经声明了
自定义构造方法的规范:
1.一定是对象方法,一定以 -开头
2.返回值一般是id类型
3.方法名一般以initWith开头
父类的属性交给父类方法去处理,子类方法处理子类自己的属性(成员变量)。
3、@category分类
分类是OC特有的,在Java中没有。
分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法。
使用注意:
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量,这里的成员变量不是Xcode自动生成的,是声明的那种,因为自动的是private类型,声明的时protected类型
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用,如果有多个category 分类都重新实现了原来类的方法,方面依据编译顺序决定调用谁的方法,谁最后编译就调用谁的方法,这是分类中的 依据,分类中方法始终比原来类中的方法优先,编译用到是.m源代码文件,.h头文件只是用来拷贝声明的。(删除框 架时,选中删除索引,不要选择删除到垃圾桶,否则这个框架就被删了。使用局部变量要初始化,全局变量和成员变量 系统默认初始化为0)
4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 -->父类
4、类的本质
1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次,因为只加载一次。先加载原始类的+load方法,再加载分类的+load方法
2.当第一次使用某个类时,就会调用当前类的+initialize方法
3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
先初始化父类,再初始化子类(先调用父类的分类+initialize方法,会覆盖父类的+initialize方法,再调用子类分类的+initialize方法,会覆盖子类的+initialize方法,如果没有分类,就调用父类和子类的+initialize方法)
5、description方法
-discription方法是NSObject自带的方法
Person* p = [[Personalloc]init];
p.age =20;
p.name =@"jack";
//默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
// 1.会调用对象p的-description方法
// 2.拿到-description方法的返回值(NSString *)显示到屏幕上
// 3. -description方法默认返回的是“类名+内存地址”
NSLog(@"%@", p);//默认输出:<Person: 0x100102c00>,即类对象和地址
NSString * name =@"rose";//输出: rose NSString类重写了NSObject的-discription方法
NSLog(@"%@", name);
// 决定类实例对象的输出结果
- (NSString *)description
{
// NSLog(@"%@", self); //会造成死循环
//stringWithFormat:拼字符串函数
return [NSStringstringWithFormat:@"age=%d, name=%@",_age,_name];
}
// 决定类对象的输出结果
+ (NSString *)description
{
// NSLog(@"%@", self); //会造成死循环
//stringWithFormat:拼字符串函数
return@"ABC";
}
6、SEL类型
SEL其实是对方法的一种包装,将方法名包装成一个SEL类型的数据,这个数据其实是函数的地址,去找对应的方法地址。找到方法地址就可以调用方法。其实消息就是SEL。
//调用方法有两种方式// performSelector:(SEL);
// @selector(test2)返回SEL类型的数据
Person * p = [[Person alloc] init];
// 间接调用test2方法---------------------------
SEL s =@selector(test2);
[p performSelector:s];
[pperformSelector:@selector(test2)];
// 直接调用test2方法---------------------------
[ptest2];
// 1.把test2包装成SEL类型的数据
// 2.根据SEL数据找到对应的方法地址
// 2.根据方法地址调用对应的方法
[ptest3:@"123"];
// performSelector:(SEL) withObject:(id)
//此处一定要注意:方法名test3:这个冒号:是函数名的一部分,不能省略
// 否则报错:-[Person test3]: unrecognized selector sent to instance SEL可以理解为selector(方法或消息)的简称
[p performSelector:@selector(test3:)withObject:@"123" ];
//***************************************************************************************
- (void)test2
{
// _cmd实际每个方法中都隐含着一个SEL数据_cmd,代表当前方法
// _cmd == @selector(test2)
// SEL数据不能直接打印,可以转为字符串再打印,
// 转换方法: NSStringFromSelector(<#SEL aSelector#>);
NSString * str =NSStringFromSelector(_cmd);
NSLog(@"test2----%@", str);
// 会引发死循环
//[self performSelector:_cmd];
}