1. 面向对象的思想
面向过程:注重实现功能的步骤;
面向对象:注重的是功能,该事物有没有该功能,只要获得该事物就会具有该功能;
角色的转换,由执行者 - - - > 控制者
类: 模具- 模型(提取一个类,创建一个类)根据自己开发需求,抽取一些属性;类的建立,
方便以后对此类的使用,不只局限于当前文件之中;考虑需求的变更
提供了属性,修改实例对象的参数;
方法,让实例对象,完成某些功能;类方法:不需要创建对象,节省内存;
方法:谁清楚,谁执行;
⚠:类方法不能访问成员变量-(只有对象方法才可以访问成员变量)
类名:前缀+大写+驼峰
对象:根据 类 提供的模具(属性,方法)创建 对应的实际事物
2.创建对象:
@interface
@end
用于声明: 声明成员变量 (可有可无)
声明实例方法 (可又可无 类方法,对象方法。注意分号)
声明成员变量的值域:@public @private @protected(默认)
方法创建: -/+ (void) person : (int) age
对应的作用: 方法类型 返回类型 方法名 继承 参数类型 参数名
@implementation
@end
类名 * 对象名 =[[]];(新建对象) 对象名字(栈)--指向-->新建对象(保存地址)
对象名:对新建对象起名,并且记录新建对象的指针,用指针访问的时候 不能直接访问,
直接可以访问是@public
@private 只能在类中访问;类对象访问不了,不能直接访问;一般在类中的方法实现set 和
get 相当于点语法
@protect 类和子类访问;
3.方法的实现
用类可以创建一个对象
person *p=[person alloc]; 创建空间
p=[p init]; 初始化
以上方法可以 等同 person *p=[[person alloc] init ];
等同 person *p=[person new];
表达式或者消息机制: [对象/类 方法名 : 参数........ ]
等同[对象的执行者 行为/功能]
类 *对象名=[创建对象/初始化];
person *p=[[person alloc]init ];
p是person类 对象 存放的是 person类的 地址;存在这指向关系;(也就是两份空间)
用p可以访问 对象的成员变量
p->_age; (直接访问,不需要set和get,注意权限)
p.age; (set和get访问)
self.age; (self区别,看方法类型;set和get)
_age; (直接访问,本类中使用)
isa指针,是对象指向类的方法列表
注意:类的设计(枚举 结构体);
匿名对象:每次用会alloc 以为这创建一个新对象;
对象-类 作为参数的本质:
⚠注意: 当自定义对象,作为成员变量
A类是B类,的成员变量
成员变量A 意味保存 A类型的地址 仅仅指向关系
外界访问,使用成员变量A,传递地址 或 自身已经有指向地址;不会自动开辟内存;
在实际应用中,会有一个变量,不断指向创建的对象的地址,每次加载数组中;
或者说,每次会索取该地址指向对象;
在编译运行出错,可以从本质入手;
学会对apple SDK开发文档使用
1.封装
封装:把事物的特性封装成抽象的类,可以隐藏内部的实现细节
访问权限-setter-getter-
⚠注意: 命名的规范;
在开发中,可能重写set方法,比如Plist的 对模型的传递
- (void)setMd:(model *)md
{
self.img.image = [UIImage imageNamed:md.icon];
self.name.text = md.name;
self.name.font = [UIFont systemFontOfSize:15];
_md = md;
}
2.点语法
点语法:本质就是set和get方法;不是访问成员变量,利用编译器特性
直接访问成员变量就一种 -> 箭头
@public 公共,权限全部开放
@private 私有的,权限是 本类;
@protected 当前类和子类,默认的权限
@package 框架;
3.self
self:在类方法之中,就代表自己当前类,在对象方法之中,就代表当前自己对象
super和self
当子类方法和父类方法一样 子类要想调用父类的方法 [self 方法名]死循环
super直接用父类方法,不用在当前对象中找
注意方法的重写时,两者的区别;
⚠注意:self类方法不能直接调用对象self方法
方法: [Person speak]; 等同于 [self speak]; (前提调用是在本类中)
成员变量: slef.age 等于 _age 等于 p-> _age; (前提调用是在本类中)
4.继承
继承:super class child class 实现功能的扩展
建立类与类之间的关系 抽取相同的代码和成员变量
子类和父类不能有相同的成员变量,父类的声明要放在子类的前面;
方法可以有相同的 ,成员变量不可以-(方法的重写) 实现的规则是:先到子类中找 找不到再到父类去找
坏处:藕合性强
功能的扩展:继承 分类 组合 ;
继承与组合的区别: A组合于B:-> B想用有A A继承B: -> A就是B
5.super
编译器指令符
super访问父类的方法,不会从当前子类找方法
使用是在子类方法(类方法-对象方法)中,调用父类的类方法或对象方法,意味必须有继承关系;
作用:使用父类的方法,功能;子类加扩展功能;(如:创建控件初始化同时加载资源;)
6.多态
多态: 用父类创建子类对象;必须有继承关系
好处: 如果参数是一个类且有子类可以传送子类的对象,
参数是父类,子类的对象也可以使用,(动态监测,传递的对象类型,执行方法,根据实际运行的对象类型调用)
动态绑定:动态绑定运行的时候确定类型,编译和运行不一样;不建议这么写(调用子类的特有方法,但是编译可以通过)
好处 代替多行代码;父类可以传入很多子类型
Person * p = [Student alloc] init ];
[p study]; study 是student 方法;
注意: 对象的类型转换 向上(父类方法)、向下 (子方法) 想转换类型 * 转换后名称=(类型 *)要转换的对象名称
[Person Class]; - - - %@ 获得当前类名;
CXLPerson * p = [[CXLStudent alloc] init];
[p eat]; //eat - person的方法
[p personSpeak];
1.ARC:AutoMatic Reference Counting(自动引用计数器)
MRC:手动引用计数
2. 内存管理:通知一个对象,我要使用你,此时计数器会加1,不用这个对象的时候让计数器会减1;
合理对内存的使用,不会造成内存的泄漏;这样就对内存进行合理的分配;
思想:当对象去 拥有或者赋值 另一个对象 此时,我们要做记录 对象被几个人占有 确定能不能被释放回收,在上述中,出现拥有
或者赋值的此时(set方法设置), 我们要记录对象占有人数,使其计数器加1,没人使用对象后要释放收回
3. 每个对象有一个 引用计数器 占用四个字节;
对象刚创建,引用计数器的值为1;
栈:先进后出 (FILO),基本数据
队列: 先进先出(FIFO):
堆: 对象数据类型,需要手动释放
4. 只要有new/alloc/copy/creat(在线程中) /retain
都需要release;有加就有减
当retainCount 为0的时候,对象会被销毁;
5. 僵尸对象: 被销毁释放的对象
野指针: 指向僵尸对象的指针;
空指针: 指向为nil的指针,运行编译不会报错;
6. dealloc方法;
- (void) dealloc //相当于,临死的遗言,对象被销毁的都是自动调用这个方法
{
[super alloc]; //arc 不能写此方法,手动管理内存需要注意,以免遗漏
}
7.内存管理的黄金法则:
⚠:多对象的时候 注意分析好 对象之间的指向关系,知道什么时候会销毁对象的位置;
换取对象的时候,注意setter方法的改变,对原对象的操作;3步曲
if(_book!=book) 1.if判断重复复制:(p=b1;p=b1;p=b1);如果为同一对象:此时不做计数
{
[_book release]; 2. 释放回收原来的对象,release旧值
_book=[book retain]; 3. 对现对象进行计数,因为开始使用新对象;retina新值
}
if(成员对象!=参数对象) 此成员对象保存的是上次对象,参数对象为新传入对象,判断同一对象
{
[ 成员对象 release]; 释放回收原来的对象
成员对象=[参数对象 retain] 1.记录新关系 计数器=1
2.传入新对象,记录;
}
8.@class头文件循环引用
如:A #import B,B #Import A,此时a中引用b,b中引用a;
如上,为循环引用;编译error
解决: 头文件引用用 @class; 此时不会有error;
#import : 会拷贝,源文件的属性,方法;由于import是一个预编译指令, 他会将""中的文件拷贝到import所在的位置
@calss: 只会告诉当前类,我有这么一个方法;不会告诉它内部的属性和方法;
当 #import 的源文件,被修改,他会重写拷贝到当前使用的类,此后,依次重写拷贝引用该文件的类;
@class 不会有上述情况;
9.内存管理循环引用问题;
A的属性中有B,B的属性有A;
在release中,两者都不会被释放;
解决1: 一个类 retain, 一个类assign
解决2: 一个类 strong, 一个类weak;
10. dealloc 方法提升
- (void)dealloc
{
self.person = nil; //用点语法,相当于调用set方法,此时会release一次;
NSLog(@"car - dealloc");
[super dealloc];
}
1. oc语法没有,私有方法
伪私有方法: 不在 @interface 中声明方法
直接在 @imelmention 实现
2. id类型
NSObject * obj 是静态数据;不能调用子类的方法
id 万能指针
id是动态类型的数据;运行的时候才检测数据的类型
id类型一般用于参数;
由于动态数据类型可以调用任意方法, 所以有可能调用到不属于自己的方法, 而编译时又不会报错, 所以可能导致运行时的错误
instancetype:
//判断stu对象 是不是CXLPerson 的实例对象 或者 子类
BOOL flag = [stu isKindOfClass:[CXLPerson class]];
//判断stu对象 是否为 CXLPerson 的实例对象 (不包括子类)
BOOL flag = [stu isMemberOfClass:[CXLPerson class]];
3.构造方法的重写
重写构造方法
1.先写父类的构造方法
2 写子类
3 调用对象为:self ----- reture self
4 返回类型为 id
不断的向上初始化父类->nsobject
作用;可以自己初始化值,同时传递或者修改一些属性;
自定义构造方法规范:需要声明
1- 一定为对象方法
2- 返回id
3- 方法名字以init开头,后面首字母,必须大写
判空
{
if( self = [super init] ) //初始化-并且赋值给--self
{
_age=age; //一般为 _下划线访问方式;编码规范
}
return self ;
}‘
4.类工厂方法创建对象
+ (instancetype)alloc; //类方法
+ (instancetype)person
{
return [[self alloc] init]; //self,不一定是本类创建对象;
}
Student *stu = [Student person]; //此时self-为Student类
self:谁调用,self就是谁
一般类方法之中,不能访问成员变量,一般不用访问成员变量的方法,优先考虑类方法
⚠注意:一个类提供自定义构造方法和自定义类工厂方法用于创建一个对象
5.SEL
SEL:相当于函数指针,打包方法,可以直接调用执行方法,可以让方法作为参数执行
1.判断有没有实现该方法
NSLog(@"%d",[stu respondsToSelector:@selector(test)]);
多用于,代理模式,是否实现了协议的方法
2.通过SEL调用方法
[stu performSelector:sel]; //无参数
[stu performSelector:sel withObject:@“123”]; //有参数
多用于监听,或者状态的改变,用SEL自动调用方法执行
6.Load和initialeize
共同点:都会先调用父类的方法,在执行本类的方法,都会执行一次,只是执行的时间不一样
Load: 当xcode编译的时候,会执行;
initialeize: 当这个类被使用的时候会调用;