OC加强-day01

 

#pragma mark - 00 知识回顾

 

1.@property + 类型 + 属性名 :执行的结果

1>在类的.m里面生成一个_属性名的属性

2>生成 _属性名 这个属性的set/get方法的声明和实现

 

注意:如果手动实现了属性的set/get方法,那么@property不会生成属性

 

 

 

2.OC是弱语言

1>什么是弱语言,编译器的容错性强,有时候代码的逻辑是错的,编译的时候只会警告不会报错

 

 

 

3.动态类型/静态类型

1>是什么?

就是一个概念而已,形容一个指针

2>什么意思?

定义一个指针,指向一个OC对象,若这个指针的类型和这个指针指向对象的类型一致,叫静态类型

定义一个指针,指向一个OC对象,若这个指针的类型和这个指针指向对象的类型不一致,叫动态类型

 

int main(int argc, const char * argv[]) {

 

//一个MKPerson类型的指针指向NSStrign类型的对象

//动态类型:这个指针的类型和这个指针指向对象的类型不一致

MKPerson *xiaoyue  = [NSString new];

//静态类型

MKPerson *xiaoyue2  = [MKPerson alloc] init];

 

return 0;

}

 

4. 编译检查/运行检查

 

"问题

int main()

{

    double num_double =  1.1;

    int *p =  &num_double;

    return 0;

}

 

pint类型的指针,但是p指向的是double类型的变量

 

1>是什么

1)编译检查: 程序运行之前的检查,就看这个对象的"类型"是否拥有某个属性/方法

2)运行检查: 程序运行过程中检查,就看这个对象的"真实类型"是否拥有某个属性/方法

 

 

"核心代码

int main(int argc, const char * argv[])

{

 

    MKPerson * xiaoyue = [[NSString alloc] init];

    //编译不报错的原因:编译检查xiaoyue 这个指针是MKPerson类型的,里面有name属性

    //运行报错的原因:运行监测xiaoyue 这个指针是NSString类型的,里面没有有name属性

    xiaoyue.name =  @"小明";

    return 0;

}

 

 

 

5. id 指针 NSObject *  的比较

 

1>相同点

都是指针,能指向任意的OC的对象

2>不同点

1)id指针能够躲避编译检查,NSObject *不能躲避

 

 

"核心代码

int main(int argc, const char * argv[]) {

    

    id xiaoyue_id = [[NSString alloc] init];

    NSObject * xiaoyue_obj = [[NSString alloc] init]; //多态

    

    [xiaoyue_id setName:@"小明"];

    //编译检测的时候检查NSObject里面有没有name属性,发现没有

    [xiaoyue_obj setName:@"小明"];

    return 0;

}

 

2)id指针是不能直接调用点语法的,如果一定要调用,需要强转

 

 

"随堂代码/00 知识回顾/5_id不能调用点语法

 

//下面代码报错

int main(int argc, const char * argv[]) {

    

    id xiaoyue_id = [[MKPerson alloc] init];

    xiaoyue_id.name = @"小明";

    

    return 0;

}

//下面代码没有问题如果强转了id类型的指针

int main(int argc, const char * argv[]) {

    

    id xiaoyue_id = [[MKPerson alloc] init];

    [xiaoyue_id setName: @"小明"];

    //

    ((MKPerson *)xiaoyue_id).name = @"小红";

    NSLog(@"%@",((MKPerson *)xiaoyue_id).name);

    return 0;

}

 

 

 

6.构造方法的复习

 

 

 

1>new方法里面做了什么 ---[[XXX alloc] init]

1)调用alloc方法,在堆区开辟空间,

2)调用init方法,初始化这块空间,把对象内所有属性成0或者nil

 

2>什么是构造方法

init方法就是构造方法

 

 

3>什么是重写构造方法

 

1)子类重写init方法,创建对象的时候调用自己重写之后的init方法

2)为什么要重写init方法

对于一个直接继承自NSObject的类,如果不重写init方法,那么对象创建的时候,对象内所有属性成0或者nil.

如果我希望创建对象的时候,里面的属性有一些事我希望的值,此时就应该重写init方法

 

MKPerson *xiaoyue = [[MKPerson alloc] init]

 

"练习

定义一个MKPerson,有一个NSString _name属性,还有一个int _age属性,

创建一个对象,这个对象一创建出来,姓名就叫@"小明",年龄就是15;

 

 

//这样写不行:这块空间没有吧真实的init,没有初始化就用了,不安全

-(instancetype)init

{

    _name = @"小明";

    _age = 15;

    return self;

    

}

//比较完美的写法

-(instancetype)init

{

    self = [super init];

    if(self != nil)//用来判断空间是否被初始化成功

    {

        _name = @"小明";

        _age = 15;

    }

    return self;

    

}

 

 

//完美的写法

-(instancetype)init

{

    

    if(self = [super init])//用来判断空间是否被初始化成功

    {

        _name = @"小明";

        _age = 15;

    }

    return self;

    

}

4>什么是自定义构造方法

是一个可以初始化当前对象的方法,可以用来实现init的功能,可以想赋予初始值的属性,通过参数传递进来

"练习

定义一个MKPerson,有一个NSString _name属性,还有一个int _age属性,

创建一个对象,这个对象一创建出来,姓名就叫什么年龄多大由调用者决定.

 

 

 

 

 

#program mark - 01 内存管理的概述 [掌握]

此知识点复习参见OC加强01视频笔记/01 内存管理的概述.pdf

 

 

"强调

1.内存分5个区,为什么OC开发只关心堆区?

1>堆区存储的是对象,不要以为对象就是Person/Student对象,一张图片/一段音频都是对象,通常比较大

2>问题不是大,关键是堆区的对象不会自动释放,如果你不手动释放,只有等到应用程序结束

 

 

2.什么时候要去释放堆区OC对象?

1>当这个OC对象没有""使用的时候,此时应该释放

2>当这个OC对象有""使用的时候,此时不应该释放

""的含义是这个对象的使用者

view就是一个对象,当需要显示view的时候就创建出来,当关闭的时候,如果以后不再使用,就应该释放

 

 

3.怎么判断一个对象有没有""在用 (对象什么时候释放)

1>OC中的对象有一个属性叫引用计数器,表示到底有多少""在使用这个对象.

2>程序员自己定义一个类创建对象,那么这个对象引用计数器为1

MKPerson *wuse = [MKPerson new];//对象引用计数器为1

3>程序员是可以控制对象的引用计数器/retainCount

1>向对象发送retain retainCount+1

2>向对象发送release retainCount-1

3>向对象发送retainCount 获取引用计数器的值

"注意

当一个对象的retainCount变为0,对象释放,操作系统才会去调用对象的dealloc方法,

 

 

4.ARCMRC

1>MRC : manual reference counting 手动引用计数 "程序员自己去管理对象的retainCount"

2>ARC : automatic reference counting 自动引用计数 "编译器帮助我们管理对象的retainCount"

3>ARCMRC的关系

1)ARC是基于MRC,本质上是相同的,都是在管理对象的retainCount.

2)ARC2011ios5,推出的

3)xcode6以后创建的项目默认是ARC

4)学习MRC原因,成为大神,必须能看懂大神的代码,大神都是从MARC走过来的.

 

#program mark - 02 1MRC程序 [掌握]

此知识点复习参见OC加强01视频笔记/02 1MRC程序.pdf

 

"强调

 

1.MRC项目,必须关闭ARC

 

2.为什么重写对象的dealloc方法,要在最后调用[super dealloc]?

 

[super dealloc]一调用,对象的这块空间,可能就不能用了!

 

 

3.注意

1>release是让对象的引用计数器-1,不是释放对象

2>dealloc方法,是对象将要释放的那一刹那调用的,操作系统在对象的retainCount0的时候自动调用的 ,程序员不要自己手动调用

 

 

 

 

#program mark - 03 内存管理的原则 [掌握]

此知识点复习参见OC加强01视频笔记/03 内存管理的原则.pdf

 

 

 

"强调

内存管理的原则

 

1.alloc/new两种方式创建出来的对象,retainCount默认为1.一般要对应一次releae,写在main函数即将结束的地方.

 

2.retain次数和release次数一定要平衡,对象被retain一次,就要release一次

 

"核心代码

int main(int argc, const char * argv[]) {

    

    MKPerson *wuse = [[MKPerson alloc] init];//1

    [wuse retain];//2

    [wuse release];//1

    [wuse release];//0

    return 0;

}

 

 

3,那个指针使用了对象,就用那个指针发送retain消息

 

4,那个指针retain了对象,就用那个指针release

"核心代码

int main(int argc, const char * argv[]) {

    

    MKPerson *wuse = [[MKPerson alloc] init];//1

    

    MKPerson *dashi = wuse;

    [dashi retain];//2

    

    

    [dashi release];//1

    [wuse release];//0

    return 0;

}

 

#program mark - 04 野指针与僵尸对象 [掌握]

此知识点复习参见OC加强01视频笔记/04 野指针与僵尸对象.pdf

 

 

"强调

1.僵尸对象和野指针的关系

1)野指针指向的不一定是对象,C语言中没有对象概念,但是有野指针的概念

int main()

{

    int *p;

    *p = 10;

    return 0;

}

2)OC,指向的是一个僵尸对象的指针叫做野指针.

 

2.僵尸对象使用注意

僵尸对象就是一块当前应用程序没有资格再去访问的堆区空间,这块空间只能由操作系统访问,访问与否,在于操作系统.

 

 

#program mark - 05 单个对象的内存管理 [掌握]

此知识点复习参见OC加强01视频笔记/05 单个对象的内存管理.pdf

 

 

"强调

1.什么是内存泄露?

一个对象在没有人使用的情况下,没有释放,始终存在于内存,当程序结束释放

2.什么时候OC对象会内存泄露 --> 违反了内存管理原则

 

1>new/alloc出来的对象,没有对应的release

 

2>retain但是没有对应的release

3>retainCount变为0之前,指针被改掉了

4>不要在对象当做参数传递的时候,在方法中随意的retain对象.

 

 

#program mark - 06 多个对象的内存管理之一 [掌握]

此知识点复习参见OC加强01视频笔记/06 多个对象的内存管理之一.pdf

 

 

 

"强调

"核心代码

int main(int argc, const char * argv[]) {

    

    MKPerson *xiaoyue = [MKPerson personWithName:@"MK"];

    MKCar *benz = [MKCar carWithSpeed:110];

    xiaoyue.car = benz;

    [xiaoyue drive];

    

    [benz release];

    [xiaoyue drive];

    [xiaoyue release];

    return 0;

}

当一个对象A拥有一个属性是另外一个对象B,如果A没有释放,此时B就不应该释放,因为B作为A的一个属性,A随时有可能调用B的方法

 

解决:调用ABset方法的时候,set方法中应该给对象B发送retain消息,Adealloc方法中给对象B发送release消息

1>

//车属性的set方法

-(void)setCar:(MKCar *)car

{

    _car = car;

    [_car retain];

}

 

 

 

-(void)dealloc

{

    NSLog(@"名字叫做%@Person对象释放了",_name);

    [_car release];

    [super dealloc];

}

 

 

#program mark - 07 多个对象的内存管理之二 [掌握] []

 

一个现象.

int main(int argc, const char * argv[]) {

    

    MKPerson *xiaoyue = [MKPerson personWithName:@"MK"];

    MKCar *benz = [MKCar carWithSpeed:110];

    

    xiaoyue.car = benz;

    [xiaoyue drive];

    

    benz.speed =  120;

    xiaoyue.car = benz;

    

    [benz release];

    [xiaoyue release];

    return 0;

}

如果重复给人对象里面的车属性赋值,导致车重复的retain

解决:在人的车属性的set方法中,对传进来的车对象进行判断,如果不是之前的车就不进行retain.

 

"核心代码

-(void)setCar:(MKCar *)car

{

    if(car != _car)

    {

        _car = car;

        [_car retain];

    }

}

 

 

#program mark - 09 多个对象的内存管理之三 [掌握]

 

现象:下面代码benz车无法释放,给人对象的车属性赋予新的值,老的值没有释放

int main(int argc, const char * argv[]) {

    

    MKPerson *xiaoyue = [MKPerson personWithName:@"MK"];

    MKCar *benz = [MKCar carWithSpeed:110];

    

    xiaoyue.car = benz;

    [xiaoyue drive];

    

    MKCar *BMW = [MKCar carWithSpeed:111];

    xiaoyue.car = BMW;

    [xiaoyue drive];

    

    [xiaoyue release];

    [benz release];

    [BMW release];

    

    

    return 0;

}

 

解决:在新的属性修改之前,对老的属性做一次release

//车属性的set/get方法

-(void)setCar:(MKCar *)car

{

    if(_car != car)

    {

        [_car release];

        _car = car;

        [_car retain];

    }

}

 

 

#program mark - 10 当属性的类型是OC对象的时候,setter方法的写法 [掌握]

此知识点复习参见OC加强01视频笔记/10 当属性的类型是OC对象的时候,setter方法的写法.pdf

 

 

注意点:

1.内存管理的目标是OC中的对象,不是OC对象是不需要进行release/retain.

2.代码优化,Person内部的NSString对象属性,也需要内存管理

 

 

posted @ 2016-07-26 15:37  MK王月  阅读(150)  评论(0编辑  收藏  举报