------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
第一讲 内存管理
1. 内存管理概念理解
1)内存管理的范围
所有的OC对象(继承自NSObject类)
2)为什么内存管理只管理OC对象?
堆中内存不连续, 无法自动释放
3)如何对OC对象进行内存管理?
所有的OC对象(继承自NSObject类)
2)为什么内存管理只管理OC对象?
堆中内存不连续, 无法自动释放
3)如何对OC对象进行内存管理?
通过操作对象的"引用计数器"
2. 引用计数器
2. 引用计数器
引用计数器概念
1)每个OC对象都有自己的引用计数器
2)它是一个整数(int类型, 占用4个字节)
3)从字面上, 可以理解为"对象被引用的次数"
4)也可以理解为: 它表示有多少人正在用这个对象
引用计数器的作用
1) 系统通过"引用计数器"来判断当前对象是否可以被释放
对象的"引用计数器"的操作方式
1)retain, +1
2)release, -1
3)retainCount, 获取对象引用计数器的值
3. dealloc方法
1)每个OC对象都有自己的引用计数器
2)它是一个整数(int类型, 占用4个字节)
3)从字面上, 可以理解为"对象被引用的次数"
4)也可以理解为: 它表示有多少人正在用这个对象
引用计数器的作用
1) 系统通过"引用计数器"来判断当前对象是否可以被释放
对象的"引用计数器"的操作方式
1)retain, +1
2)release, -1
3)retainCount, 获取对象引用计数器的值
3. dealloc方法
1)当对象即将被销毁, 系统自动给对象发送一条dealloc消息
2)因此, 从dealloc方法有没有被调用, 就可以判断出对象是否被销毁
3)重写了dealloc方法, 必须调用[super dealloc], 并且放在最后面调用
4)不要自己直接调用dealloc方法
3)重写了dealloc方法, 必须调用[super dealloc], 并且放在最后面调用
4)不要自己直接调用dealloc方法
重写dealloc方法,代码规范
(1) 一定要[super dealloc],而且要放到最后,意义是:先释放子类占用的空间在释放父
类占用的空间
(2)对self(当前)所拥有的的其他对象做一次release操作
-( void) dealloc{
[_car release];
[super dealloc];
}
4. 多对象内存管理
类占用的空间
(2)对self(当前)所拥有的的其他对象做一次release操作
-( void) dealloc{
[_car release];
[super dealloc];
}
4. 多对象内存管理
-(void)setCar:(Car*)car{
_car = car;
}
对象已经释放了,再次去使用
[car release];
[p driver]; // _car = [car retain];
给p.car 设置不同对象的时候会造成原对象内存泄露
p.car = car1;
[car1 release]; //car1 1
p.car = car2; // [_car release]; _car = [car retain];
//
p.car = car1; //car1 2
[car1 release]; // 1
p.car = car1; // if(_car != car){_car release]; _car = [car retain];}
5. @property的修饰关键字
_car = car;
}
对象已经释放了,再次去使用
[car release];
[p driver]; // _car = [car retain];
给p.car 设置不同对象的时候会造成原对象内存泄露
p.car = car1;
[car1 release]; //car1 1
p.car = car2; // [_car release]; _car = [car retain];
//
p.car = car1; //car1 2
[car1 release]; // 1
p.car = car1; // if(_car != car){_car release]; _car = [car retain];}
5. @property的修饰关键字
1)控制set方法的内存管理
retain: release旧值, retain新值(用于OC对象),要配合nonatomic使用
assign: 直接赋值, 不做任何内存管理(默认, 用于非OC对象类型)
copy: release旧值, copy新值(一般用于NSString *)
2)控制是否需要生成set方法
readwrite: 同时生成set方法和get方法(默认)
readonly: 只会生成get方法
3)多线程管理
atomic: 性能低(默认)
nonatomic: 性能高(为iOS系统开发软件建议使用,为mac开发软件可以使用atomic)
4)控制set方法和get方法的名称
setter: 设置set方法的名称, 一定有个冒号:
getter: 设置get方法的名称
6. @class用法
retain: release旧值, retain新值(用于OC对象),要配合nonatomic使用
assign: 直接赋值, 不做任何内存管理(默认, 用于非OC对象类型)
copy: release旧值, copy新值(一般用于NSString *)
2)控制是否需要生成set方法
readwrite: 同时生成set方法和get方法(默认)
readonly: 只会生成get方法
3)多线程管理
atomic: 性能低(默认)
nonatomic: 性能高(为iOS系统开发软件建议使用,为mac开发软件可以使用atomic)
4)控制set方法和get方法的名称
setter: 设置set方法的名称, 一定有个冒号:
getter: 设置get方法的名称
6. @class用法
@class
.h @class Dog
.m #import "Dog.h"
@class和#import的区别
通过@class解决循环依赖问题
7. 内存管理时的循环retain问题
.h @class Dog
.m #import "Dog.h"
@class和#import的区别
通过@class解决循环依赖问题
7. 内存管理时的循环retain问题
解决办法: 一端用retain、一端用assign
注意: 使用了assign后, dealloc中就不需要release了
8. 对象自动释放池的使用
注意: 使用了assign后, dealloc中就不需要release了
8. 对象自动释放池的使用
对于autorelease pool本身,会在如下两个条件发生时候被释放
1)手动释放Autorelease pool
2) Runloop结束后自动释放
对于autorelease pool内部的对象
在引用计数的retain == 0的时候释放。 release和autorelease pool 的 drain都会触发retain--事件。
1)手动释放Autorelease pool
2) Runloop结束后自动释放
对于autorelease pool内部的对象
在引用计数的retain == 0的时候释放。 release和autorelease pool 的 drain都会触发retain--事件。
1、autorelease使用注意
1)并不是放到自动释放池代码中,都会自动加入到自动释放池,不管这个对象是在自动释放池内还是外创建的,只要在自动释放池内写一个 [p1 autorelease];p1就会被放到自动释放池中。注意autorelease是一个方法,且只有在自动释放池中使用才有效。
2、autorelease错误用法
( 1)连续调用多次autorelease,释放池销毁时执行两次release(-1)吗
( 2) Alloc之后调用了autorelease,之后又调用了release。
9、应用:创建一个学生类,初始化年龄
student.h
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property(nonatomic,assign) int age;
-(instancetype)initWithAge:(int)age;
+(instancetype)studentWithAge:(int)age;
@end
student.m
#import "Student.h"
@implementation Student
- (void)dealloc
{
NSLog(@"Student 被释放");
[super dealloc];
}
//自定义构造方法
-(instancetype)initWithAge:(int)age{
if (self = [super init]) {
_age = age;
}
return self;
}
//自定义初始化方法
+(instancetype)studentWithAge:(int)age{
return [[[self alloc] initWithAge:age] autorelease];
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Student *stu = [[[Student alloc] initWithAge:10] autorelease];
Student *stu1 = [Student studentWithAge:100];
NSLog(@"age = %d",stu1.age);
}
return 0;
}
10、ARC
自动引用计数,即ARC,当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease
判断准则:
只要没有强指针指向对象,对象就会被释放。
1)强指针
所有的指针默认就是强指针
强指针使用 strong 标识
2)弱指针
所有的指针默认就是强指针
弱指针使用__week 标识
循环引入的对象中其中一个对象设置为 strong 另一个设置为 weak
ARC中的@property
strong : 用于OC对象, 相当于MRC中的retain
weak : 用于OC对象, 相当于MRC中的assign
assign : 用于基本数据类型, 跟MRC中的assign一样
copy : 一般用于NSString, 跟MRC中的copy一样
在ARC情况下解决”循环retain” 的问题: @property一边用strong,一边用weak。
第二讲 blocks
1、block概念
可执行代码,Block对象包含着一组状态数据,
这些数据在程序执行时用于对行为产生影响。
这些数据在程序执行时用于对行为产生影响。
2、使用方法
1) block最简单形式
定义格式:
void (^block名)() = ^{代码块;}
使用格式:block名();定义格式:
void (^block名)() = ^{代码块;}
2) block带有参数的block的定义和使用
格式:
void (^block名称)(参数列表)= ^ (参数列表) { // 代码实现; }
3) 带有参数和返回值的block
格式:
返回类型 (^block名称)(参数列表)= ^ 返回类型 (参数列表) { // 代码实现; }
格式:
返回类型 (^block名称)(参数列表)= ^ 返回类型 (参数列表) { // 代码实现; }
3、block的typedef
利用typedef定义block类型(和指向函数的指针很像)
格式:
Typedef int(^MyBlock)(int ,int);
速记符
typedef 返回值类型 (^block变量名)(参数类型列表);
格式:
Typedef int(^MyBlock)(int ,int);
速记符
typedef 返回值类型 (^block变量名)(参数类型列表);
4、 block访问外部变量
1)在block内部可以访问block外部的变量
2)在block内部不可以修改block外部的变量
2)在block内部不可以修改block外部的变量
3)给局部变量加上__block关键字,则这个局部变量可以在block内部进行修改。
5、block使用技巧及注意
1) block 结构的快速提示:inlineBlock
2) block变量用作方法的参数的时候,最好把参数类型列表部分加上 具体的形参名