------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1.为什么要管理内存:
3)每一个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”即有多少人在使用这个对象.
4)当一个对象的计数器值是0时,对象占用的内存会被系统回收,换句话说,如果对象的计数器不为0,那么在整个程序运行的过程,它占用的内存就不可能被回收,除非整个程序已经退出。
5)引用计数器的操作
1.retain :计数器+1,会返回对象本身
2.release :计数器-1,没有返回值
3.retainCount :获取当前的计数器
4.dealloc
* 当一个对象要被回收的时候,就会调用
* 一定要调用[super dealloc],这句调用要放在最后面
1> 僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用(-[Person setAge:]: message sent to deallocated instance 0x100109a10)
2> 野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
3> 空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
p = nil;
OC不存在空指针错误,给空指针发送消息,不报错
#import "Person.h"
@implementation Person
// 当一个Person对象被回收的时候,就会自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end
dealloc方法的代码规范
1> 一定要[super dealloc],而且放到最后面
2> 对self(当前)所拥有的其他对象做一次release
- (void)dealloc
{
[_car release];
[super dealloc];
}
1>你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)
2>你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
3>谁retain,谁release
4>谁alloc,谁release
2.set方法的内存管理
1).set方法的代码规范
1> 基本数据类型:直接复制
- (void)setAge:(int)age
{
_age = age;
}
2> OC对象类型
- (void)setCar:(Car *)car
{
// 1.先判断是不是新传进来对象
if ( car != _car )
{
// 2.对旧对象做一次release
[_car release];
// 3.对新对象做一次retain
_car = [car retain];
}
}
只要调用了alloc,必须有release(autorelease)
对象不是通过alloc产生的,就不需要release
1> _speed :直接访问成员变量
2>self->_speed :直接访问成员变量
3>self.speed : get方法
4>[self speed] : get方法
3.@property参数
1)@property (retain)Book *book;
- (void)setBook:(Book *)book
{
if (_book != book)
{
[_book release];
_book = [book retain];
}
}
retain : 生成的set方法里面,release旧值,retain新值
2)@property参数
.set方法内存管理相关的参数
* retain : release旧值,retain新值(适用于OC对象类型)
* assign : 直接赋值(默认,适用于非OC对象类型)
* copy : release旧值,copy新值
是否要生成set方法
* readwrite : 同时生成setter和getter的声明、实现(默认)
* readonly : 只会生成getter的声明、实现
多线程管理
* nonatomic : 性能高 (一般就用这个)
* atomic : 性能低(默认)
setter和getter方法的名称
* setter : 决定了set方法的名称,一定要有个冒号 :
* getter : 决定了get方法的名称(一般用在BOOL类型)
/*
文件名:User.h
*/
#import
typedef enum {
SexMan, // 男
SexWoman // 女
} Sex;
typedef struct {
int year;
int month;
int day;
} Date;
// 姓名、微博号码、密码、头像、性别、手机、生日
@interface User : NSObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *account;
@property (nonatomic, retain) NSString *password;
// http://weibo.com/a.png URL
@property (nonatomic, retain) NSString *icon;
@property (nonatomic, assign) Sex sex;
@property (nonatomic, retain) NSString *phone;
@property (nonatomic, assign) Date birthday;
@end
*******************************************************************
/*
文件名:User.m
*/
#import "User.h"
@implementation User
- (void)dealloc
{
[_name release];
[_account release];
[_icon release];
[_password release];
[_phone release];
[super dealloc];
}
@end
*******************************************************
/*
文件名:Status.h
*/
#import
#import "User.h"
// 微博内容、微博配图、发送时间、微博发送人、转发的微博、被评论数、被转发数
@interface Status : NSObject
@property (nonatomic, retain) NSString *text;
@property (nonatomic, retain) NSString *icon;
// 从1970-01-01 00:00:00 开始,一共度过了多少毫秒
@property (nonatomic, assign) long time;
//@property (nonatomic) time_t time;
@property (nonatomic, retain) User *user;
@property (nonatomic, retain) Status *retweetStatus;
@property (nonatomic, assign) int commentsCount;
@property (nonatomic, assign) int retweetsCount;
@end
***********************************************************
/*
文件名:Status.m
*/
#import "Status.h"
@implementation Status
- (void)dealloc
{
[_text release];
[_user release];
[_retweetStatus release];
[_icon release];
[super dealloc];
}
@end
*****************************************************
// main.m
// 06-模型设计练习
#import
#import "User.h"
#import "Status.h"
int main()
{
// 新建2个用户
User *u = [[User alloc] init];
u.name = @"2B";
User *u2 = [[User alloc] init];
u2.name = @"傻B";
// 新建2条微博
Status *s = [[Status alloc] init];
s.text = @"今天天气真好!";
s.user = u;
Status *s2 = [[Status alloc] init];
s2.text = @"今天天气真的很好!";
s2.retweetStatus = s;
s2.user = u2;
[u2 release];
[u release];
[s2 release];
[s release];
return 0;
}
4.循环引用
2)两端循环引用解决方案
1> 一端用retain
2> 一端用assign
3)开发中引用一个类的规范
1> 在.h文件中用@class来声明类
2> 在.m文件中用#import来包含类的所有东西
@class的作用:仅仅告诉编译器,某个名称是一个类
5.autorelease
1).autorelease的基本用法
1> 会将对象放到一个自动释放池中
2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3> 会返回对象本身
4> 调用完autorelease方法后,对象的计数器不变
2).autorelease的好处
1> 不用再关心对象释放的时间
2> 不用再关心什么时候调用release
3).autorelease的使用注意
1> 占用内存较大的对象不要随便使用autorelease
2> 占用内存较小的对象使用autorelease,没有太大影响
4).错误写法
1> alloc之后调用了autorelease,又调用release
@autoreleasepool
{
// 1
Person *p = [[[Person alloc] init] autorelease];
// 0
[p release];
}
2> 连续调用多次autorelease
@autoreleasepool
{
Person *p = [[[[Person alloc] init] autorelease] autorelease];
}
5).自动释放池
1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
6).自动释放池的创建方式
1> iOS 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool release]; // [pool drain];
2> iOS 5.0 开始
@autoreleasepool
{
}
系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
1> 创建对象时不要直接用类名,一般用self
6.ARC
1)ARC特点
1> 不允许调用release、retain、retainCount
2> 允许重写dealloc,但是不允许调用[super dealloc]
3> @property的参数
* strong :成员变量是强指针(适用于OC对象类型)
* weak :成员变量是弱指针(适用于OC对象类型)
* assign : 适用于非OC对象类型
4> 以前的retain改为用strong
2)指针分2种:
1> 强指针:默认情况下,所有的指针都是强指针 __strong
2> 弱指针:__weak
ARC的判断准则:只要没有强指针指向对象,就会释放对象
3)ARC循环引用解决方案
当两端循环引用的时候,解决方案:
1> ARC
1端用strong,另1端用weak
2> 非ARC
1端用retain,另1端用assign
7.Black
1> 如何定义block变量
int (^sumBlock)(int, int);
void (^myBlock)();
2> 如何利用block封装代码
^(int a, int b) {
return a - b;
};
^() {
NSLog(@"----------");
};
^ {
NSLog(@"----------");
};
3> block访问外面变量
* block内部可以访问外面的变量
* 默认情况下,block内部不能修改外面的局部变量
* 给局部变量加上__block关键字,这个局部变量就可以在block内部修改
4> 利用typedef定义block类型
typedef int (^MyBlock)(int, int);
// 以后就可以利用MyBlock这种类型来定义block变量
MyBlock block;
MyBlock b1, b2;
b1 = ^(int a, int b) {
return a - b;
};
MyBlock b3 = ^(int a, int b) {
return a - b;
};
8.@protocol
1)协议的定义
@protocol 协议名称 <NSObject>
// 方法声明列表....
@end
2)如何遵守协议
1> 类遵守协议
@interface 类名 : 父类名 <协议名称1, 协议名称2>
@end
2> 协议遵守协议
@protocol 协议名称 <其他协议名称1, 其他协议名称2>
@end
3)协议中方法声明的关键字
1> @required (默认)
要求实现,如果没有实现,会发出警告
2> @optional
不要求实现,怎样不会有警告
4)定义一个变量的时候,限制这个变量保存的对象遵守某个协议
类名<协议名称> *变量名;
id<协议名称> 变量名;
NSObject<MyProtocol> *obj;
id<MyProtocol> obj2;
如果没有遵守对应的协议,编译器会警告
5)@property中声明的属性也可用做一个遵守协议的限制
@property (nonatomic, strong) 类名<协议名称> *属性名;
@property (nonatomic, strong) id<协议名称> 属性名;
@property (nonatomic, strong) Dog<MyProtocol> *dog;
@property (nonatomic, strong) id<MyProtocol> dog2;
6)协议可用定义在单独.h文件中,也可用定义在某个类中
1> 如果这个协议只用在某个类中,应该把协议定义在该类中
2> 如果这个协议用在很多类中,就应该定义在单独文件中
7)分类可用定义在单独.h和.m文件中,也可用定义在原来类中
1> 一般情况下,都是定义在单独文件
2> 定义在原来类中的分类,只要求能看懂语法