OC基础day06
**问题 :
init初始化初始化默认值
和 类初初始化的区别
调用时 子类父类类方法是必须要用父类的类方法名
才能调用
而init子类也可以调用init对象方法名**
NSObject 是所有类的根类
super
- 重写: 重新实现父类继承过来的方法
- super 可以在子类中调用父类的方法
- super 能不能再类方法中使用?
- 可以 如果子类的类方法中使用那么super调用的就是父类的类方法
- 在子类调用对象方法中用super 就是调用的父类的对象方法
- 私有变量: @private修饰的叫做私有变量
- 真 私有变量就是写在.m中声明的成员变量
- 私有方法 在 .m 中实现而不再 .h 中声明
- description方法
- NSLog(@”%@”,对象的指针);
- %@打印对象的指针的时候 本质上
- 调用了这个对象的 - (NSString *)description 返回一个字符串 在把这个字符串打印到控制台
- -(NSString *description 是在NSObject他的默认返回值”<对象所属的类名:对象的地址>”
- 所以我们有时候需要重写 这个类的-(NSStrong *)description
- 目的、: 是用%@可以快速打印这个对象信息
- 里氏替换原则
- 父类指针 可以指向子类的对象
- 多态
- 对于同一个行为的多种变现形式
- 有继承关系
- 有方法重写
- 有父类指针指向子类对象
- 对于同一个行为的多种变现形式
- 类的本质: 是一个对象 是一个名字叫做Class 这个类的对象
- [对象 class]
- [类名 class]
- SEL是一种书数据类型
- SEL sel; SEL 使用来保存类的方法
- SEL sel = @selector(方法名);
-
* 点语法*
- 点语法 :相当于调用方法
对象名.name = @"xxx";
//相当于 [对象名 setName:@"xxx"];
NSString *name = [对象名 name];
NSString *name = 对象名.name;
总结: 点语法的适应
- 如果点语法出现在赋值符号左边相当于赋值
那么这个语法相当于 setXxx方法
如果点语法出现在赋值符号右边相当于取值
- 那么相当于 使用 getXxx
点语法注意事项
- 点语法 : 是Xcode的特性 在编译之前 xcode会把点语法替换成对象方法
- 对象.那么 = @”zhangSan”=======>[对象 setName:@”zhangSan”];
- 所以说在使用点语法之前 必须有对象方法
@property的使用
- 在xcode 4.4之前 @property 只能生成setter和getter的声明
- @synthesize只能生成 setter和getter的实现
- 必须两个同时使用 生成的是私有属性
*@property增强 - 格式: @perperty 数据类型 去掉下划线的属性名
- 自动生成getter和setter的声明和实现
- 不会生成不带下划线,而会生成带有下划线的(如果不村子啊)
- 使用@property注意
- 生成的数据类型是 带有下划线的真有属性 @protected
- 生成的setter和getter是直接赋值和直接返回的
- 所以如果想要进行逻辑判断 直接在.m中做逻辑判断
- 如果同时声明加逻辑判断 就需要在.m中添加一个属性
任意的指针可以指向任意的对象
- OC是一门弱语言 编译器对源代码的容错性较强 一些逻辑错误只是报警告不会报错
- 若语言的缺点
- 如果有逻辑错误编译可以通过 运行不通过
- 动态类型和静态类型
- 静态类型: 什么样的指针就指向什么样的对象
- 动态类型: 指针的类型和指针指向的真是类型不一致
编译检查 运行检查
什么是编译检查
- 编译检查: 程序运行之前的检查, 就看这个指针定义的时候类型是否拥有某个方法/属性
- 运行检查:程序运行过程中检查, 见这个指针指向的对象的类型是否拥有某个方法的实现
编译看左边 运行看右边
口诀: 编译时看左边,运行时看右边
NSString * str = [Dog new];//不会报错,OC弱语法
调用方法:
[str eat];//编译的时候报错[str length];//编译的时候不会报错,运行时报错
[(Dog *)str eat];//编译的时候 不会报错,运行时也不会报错
报错信息:
reason: ‘-[Dog miaomiao]: unrecognized selector sent to instance 0x100501430’
这种信息通常表示 运行时对象没有 上面说的那个”miaomiao”方法
编译的时候 编译器说了算
运行的时候 运行时说了算
NSObject万能指针
- NSObject是一个万能指针
- 可以指向任何对象,编译不会报错(因为OC是若语法)也不会警告(里氏替换原则)
#import "HMPerson.h"
//HMPerson类中有一个方法 叫做 - lenght
@interface HMPerson : NSObject
@property NSString * name;
- (NSUInterger)length;
@end
@implementation HMPerson
- (NSUInterger)length
{
return 10;
}
@end
int main(int argc, const char * argv[]) {
NSObject *obj = @"1234";//万能指针 指向了一个 OC字符串对象
// [obj length];报错 因为编译时只看指针的类型,没有lenght方法 所以报错
unsigned long len = [(HMPerson *)obj length];
NSLog(@"%lu",len);//编译直接报错 解决[(NSString *)obj length]
return 0;
}
"NSObject * 指针有一个缺点
NSObject * 指针指向了一个自己定义的对象的时候,想通过这个指针调用自己定义的对象的方法时
必须强转,避免编译器报错
id指针
- id类型 是一个typedef过的指针类型
- 所以声明的时候不需要加*
- id和NSObject* 都是万能指针 他们的区别在于
- 指针类型的NSObject* 编译的时候会做编译检查 如果想编译通过必须进行强制转换
- id指针 编译时直接通过
- id指针的缺点
- 优点: 不做任何编译检查
- 缺点: 不做任何编译检查
- 不能通过 id 指针 使用点语法 但可以使用 getter和setter方法
instancetype
- 写一个与类同名的类方法/带有参数的方法
+ (Person *)person;//personWithXxx
+ (Dog *)dog;
- 返回值如果是这个类的本身的对象 那么就是instancetype 表示这个类本身的对象
- id和instancetype的区别
- instancetype 只能作为方法的返回值
- id指针 是一个万能指针 通常id可以用来定义一个可以指向任何对象的指针变量
-
在对象方法中使用self创建当前类的对象
1.Person * pp = [Person new];
我要拿到Person类的类对象
[pp class];
[Person class];
2.在Person类中有一个方法
- (void)test
{
//在此方法中创建一个Person对象
//1.Person * p1 = [Person new]
//2.Person * p2 = [self new];//不行,对象方法中self'表达对象
//先获取到类对象
Class clazz = ;
[clazz new];//就是当前类的对象
// 合成一句话
[self.class new];//self.class ===>[self class]
}
动态类型检测
- 判断一个指针所指向的对象 能不能响应这个方法(可以有声明但是必须有实现)
BOOLrespondsToSelector:(SEL)aSelector;
Person *pp = [Person new];
[pp respondsToselector:@selector(方法名)];*****
```
- 判断一个对象 是不是指定类的对象 或者它子类的对象
(BOOL)isKindOfClass:(Class)aClass;
- 判断一个对象 是不是指针类的对象 不包括子类对象
(BOOL)isMemberOfClass:(Class)aClass;
- 判断一个类 是不是指定类的子类
+(BOOL)isSubclassOfClass:(Class)aClass;
**构造方法**
- new方法的内部干了三件事
- 在堆区开辟空间
- 初始化
- 返回空间地址
- 其实new方法内部什么都没干,调用了两个方法
- alloc方法==> 1>在堆区开辟空间
- init方法==> 2>初始化
有一个类 Person类
创建对象 Person * p1 = [Person new];
Person * p2 = [[Person alloc] init]
/*
Person * pp = [Person alloc];
Person * zhangsan = [pp init];
*/
**重写init方法**
- 重写init方法的目的
- init方法是在NSObject中定义,默认实现给属性赋值都是0
- 为了让一个对象创建出来就有固定的值 我们必须重写构造方法
//代码必须按照以下代码
- (instancetype)init
{
if(self = [super init])
{
// 子类自己要写的一些代码
self.name = @”lidain”;
}
return self ;
}
“`
- 目的: 初始化对象的时候我们可以指定
自定义构造方法
- 可以根据需求 自己指定初始化对象后的属性值
- 自定义方法的规范
- 必须是 initWithXxx开头
- 也要在initWithXxx 方法中用super方法
- 自定义构造方法的使用注意
- 子类中 我们一般不做父类继承过来的属性的初始化
- 子类只初始化自己特有的属性,及成果来的属性通过[super initWithXxx]来初始化父类继承过来的属性