内存管理(3)
来源:互联网 发布:移动网络玩游戏卡吗 编辑:程序博客网 时间:2024/06/05 23:57
10、【掌握】@property参数(一)
@property 4.4前
- 1) @property + 手动实现
- 2) @property int age; + @synthesize age;//get和set方法的声明和实现都帮我们做了
- 3) @property int age + @synthesizes age = _b;
@property 4.4增强 .h
- @property int age;
- 1) 生成_age
- 2) 生成_age的get和set方法的声明
- 3) 实现_age的get和set方法
1.@property参数
- 格式:@property (参数1,参数2) 数据类型 方法名
// 基本数据类型int _age;// set方法的写法-(void)setAge:(int) age{_age = age;}// 用assign修饰后,仍旧会生成以上标准的set方法@property (assign) int age;// oc对象类型@property (retain) Car *car ;// 用retain修饰后,生成如下内存管理代码-(void)setCar:(int) car{ if(_car ! = car) { [_car release]; _car = [car retain]; }}
1.内存管理相关参数
- retain : release旧值,retain新值(用于OC对象)
- assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
- copy : release旧值,copy新值(一般用于NSString *)
验证assign如果作用在对象上,实际上就是直接赋值
//使用@property增强型 生成get和set方法@property(nonatomic,assign)Car *car;//.m文件中实际上生成的是- (void)setCar:(Car *)cat{ _car = car; //当对象release后,将无法使用该对象}// main函数int main(){ Person *p = [Person new]; Car *c = [Car new]; // 给人一辆车 p.car = c; // 释放车 [c release]; // 让人开车 [p drive]; //此时p指向了僵尸对象}
- 使用@property增强型 生成get和set方法
//使用@property增强型 生成get和set方法@property(nonatomic,retain)Car *car;//.m文件中实际上生成的是- (void)setCar:(Car *)cat{ if(_car != car) { [_car release]; _car = [car retain]; }}// main函数int main(){ Person *p = [Person new]; Car *c = [Car new]; // 给人一辆车 p.car = c; // 释放车 [c release]; // 让人开车 [p drive];}
- 此时,会发生内存泄露。
- 解决办法
- (void)dealloc{ NSLog(@"Person -- dealloc"); [_car release]; [super dealloc];}
11.【掌握】@property参数(二)
1.@property 参数(二)
1、是否要生成set方法(若为只读属性,则不生成)
- readonly:只读,只会生成get的声明和实现
- readwrite:默认的,同时生成set和get的声明和实现
2.多线程管理(苹果在一定程度上屏蔽了多线程操作)
- nonatomic:高性能,一般使用这个
atomic:低性能,默认
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
3.set和get方法的名称
- 修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改 名称一般用在布尔类型中的getter。
控制set方法和get方法的名称setter : 设置set方法的名称,一定有个冒号:getter : 设置get方法的名称@property(nonatomic,assign, setter=abc:,getter=haha)int age
可以理解为:
- [p setAge: ]——> [p abc:],
- [p age] ———> [p haha];
- p.age 不会报错(内部优化)
“`objc
@property(nonatomic,assign, setter=setVip:,getter=isVip) BOOL vip;
![](http://img.blog.csdn.net/20161009213635575)* 用法: 设置值![](http://img.blog.csdn.net/20161009213720825)* 获取值![](http://img.blog.csdn.net/20161009213749107)##12、【理解】应用:电商App练习####电商App类的设计* 要求:利用OC+面向对象设计下面的三个类:* 一、商品类-Goods * 属性: 商品名称 * 单价 * 重量 * 商品展示图片 * 生产日期(暂时用结构体表示)produceDate * 过期日期 expireDate* 二、买家类(用户) Buyer * 属性: * 姓名 * 性别(枚举) * 年龄 * 身高(单位:cm)* 三、卖家类 - Seller * 属性: * 姓名 * 性别(枚举) * 年龄 * 身高(单位:cm) * 所出售商品(假设一个卖家就卖一件商品)* 四、买家类、卖家类(抽象父类Person)* 五、在main函数中创建卖家、商品、买家类的对象。```objc// 创建一个表示日期时间的结构体typedef struct{ int hour; int min; int sec;}Time;//表示日期typedef struct{ int year; int month; int day; Time time; }MyDate;MyDate produceDate = (MyDate){2011, 9, 10, {15, 16, 30}}; //注意,这句话是错误的<div class="se-preview-section-delimiter"></div>
- 原因是:
- goods.expireDate—–>得到这个成员expireDate的值,是结构体类型
- expireDate.Time 这是访问结构体变量,time的值
- goods.expireDate.time 会被误认为是点语法,导致出错
// 创建一个表示性别的枚举typedef enum{ GenderMale, // 男 GenderFemale // 女} Gender;
![](image1/12.1.png)* 原因是: * goods.expireDate----->得到这个成员expireDate的值,是结构体类型 * expireDate.Time 这是访问结构体变量,time的值 * goods.expireDate.time 会被误认为是点语法,导致出错```objc// 创建一个表示性别的枚举typedef enum{ GenderMale, // 男 GenderFemale // 女} Gender;<div class="se-preview-section-delimiter"></div>
13、【理解】@class的使用
- 场景
1.@class的使用
- 作用
- 可以简单地引用一个类
- 简单使用
- @class Dog; //类的引入
- 仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容
具体使用
- 在.h文件中使用@class引用一个类
- 在.m文件中使用#import包含这个类的.h文件
如下面代码:
A.h文件 #import "B.h" @interface A : NSObject { B *b; } @end
- 为了简单起见:A类是引用类,B类是被引用类,这里先不考虑A类的实现文件。
通常引用一个类有两种办法:
- 一种是通过#import方式引入;
- 另一种是通过@class引入;
这两种的方式的区别在于:
1)#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在 A.h文件中 B *b只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息;
2)使用@class方式由于只需要知道被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以需要使用#import来包含被引用类的头文件;
3)通过上面2点也很容易知道在编译效率上,如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt(A->B, B->C,C->D…),一旦最开始的头文件稍有改动,后面引用到这个文件的所有类 都需要重新编译一遍,这样的效率也是可想而知的.而相对来讲,使用@class方式就不会出现这种问题了;
所以:我们实际开发中尽量在.h头文件中使用@class
- 4)对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类,B类的代码:
- 当程序运行时,编译会报错,当使用@class在两个类相互声明,就不会出现编译报错。
* 把其中的一个头文件中的import换成@class
* 面试题:#import和@class的区别。
* 作用上的区别
* import会包含引用类的所有信息(内容),包括引用类的变量和方法 @class仅仅是告诉编译器有这么一个类,具体这个类里有什么信息,完全不知道。
* 效率上的区别
* 如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,编译效率非常低相对来讲,使用@class方式就不会出现这种问题了。
##13、【理解】@class的使用* 场景![](http://img.blog.csdn.net/20161009214217550)####1.@class的使用* 作用 * 可以简单地引用一个类* 简单使用 * @class Dog; //类的引入 * 仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容* 具体使用 * 在.h文件中使用@class引用一个类 * 在.m文件中使用#import包含这个类的.h文件* 如下面代码:```objc A.h文件 #import "B.h" @interface A : NSObject { B *b; } @end<div class="se-preview-section-delimiter"></div>
- 为了简单起见:A类是引用类,B类是被引用类,这里先不考虑A类的实现文件。
通常引用一个类有两种办法:
- 一种是通过#import方式引入;
- 另一种是通过@class引入;
这两种的方式的区别在于:
1)#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在 A.h文件中 B *b只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息;
2)使用@class方式由于只需要知道被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以需要使用#import来包含被引用类的头文件;
3)通过上面2点也很容易知道在编译效率上,如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt(A->B, B->C,C->D…),一旦最开始的头文件稍有改动,后面引用到这个文件的所有类 都需要重新编译一遍,这样的效率也是可想而知的.而相对来讲,使用@class方式就不会出现这种问题了;
所以:我们实际开发中尽量在.h头文件中使用@class
- 4)对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类,B类的代码:
- 当程序运行时,编译会报错,当使用@class在两个类相互声明,就不会出现编译报错。
- 把其中的一个头文件中的import换成@class
- 面试题:#import和@class的区别。
- 作用上的区别
- import会包含引用类的所有信息(内容),包括引用类的变量和方法 @class仅仅是告诉编译器有这么一个类,具体这个类里有什么信息,完全不知道。
- 效率上的区别
- 如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,编译效率非常低相对来讲,使用@class方式就不会出现这种问题了。
14、【理解】循环retain问题
循环retain的使用
- 问题:人有一只狗,狗有一个主人。
class "Dog.h";@interface Person :NSObject@property(nonatomic,retain)Dog *dog;@end@class "Person.h";@interface Dog:NSObject@property(nonatomic,retain)Person *owner;@end//main.m//创建对象Dog *d = [Dog new];Person *p = [Person new];//循环引用p.dog = d;d.owner = p;//看似正确的释放代码[d release];[p release];<div class="se-preview-section-delimiter"></div>
程序执行结果: p和d都没有被释放掉
原理分析:
p.dog = d; //因为dog的set方法中是 进行了 [dog retain];dog2d.owner = p;//会让p的引用计数+1 owner2当执行了[d release];[p release];dog和owner 的引用计数变成1
如图:
循环retain的场景
- 比如A对象retain了B对象,B对象retain了A对象
- 循环retain的弊端
- 这样会导致A对象和B对象永远无法释放
循环retain的解决方案
- 当两端互相引用时,应该一端用retain、一端用assign
* 程序执行结果: p和d都没有被释放掉* 原理分析:![](http://img.blog.csdn.net/20161009215834728)```objcp.dog = d; //因为dog的set方法中是 进行了 [dog retain];dog2d.owner = p;//会让p的引用计数+1 owner2当执行了[d release];[p release];dog和owner 的引用计数变成1
- 如图:
循环retain的场景
- 比如A对象retain了B对象,B对象retain了A对象
- 循环retain的弊端
- 这样会导致A对象和B对象永远无法释放
循环retain的解决方案
- 当两端互相引用时,应该一端用retain、一端用assign
- 内存管理(3)
- 内存管理(3)
- 内存管理(3)
- 操作系统------内存管理(3)
- 内存管理(3)用户空间内存管理&内存区对象
- 内存管理(3):如何优化内存使用
- object c内存管理(3)
- Arm-linux内存管理(3)
- C++内存管理学习笔记(3)
- cocos2dx 内存管理(3)---CCPoolManager浅析
- C/C++内存管理(3)
- iOS面试题(3)----内存管理
- cocos2d-x 内存管理(3)
- Linux内存管理(3)
- 内存管理[3]
- 内存管理3GB
- linux 内存管理3
- java内存管理3
- 比较经典的中断串口接口的方法
- openssl.cnf
- CSS3快速上手之7:线性渐变+各种分布
- 《深入理解计算机系统》第一章 计算机系统漫游
- 数据库驱动以及url
- 内存管理(3)
- Node.js的异步I/O
- 深入研究java.lang.Class类
- 局部内部类为什么只能访问final局部变量,对于成员变量却可以随便访问?
- Latex 之table
- 字符编码之Base64/32/16编码
- Linux 下创建Oracle表空间
- LeetCode 第十九题 Remove Nth Node From End of List
- Memcache常见问题集