属性与内存管理(属性与内存管理都是相互关联的)

<span style="font-size:18px;">
属性与内存管理(属性与内存管理都是相互关联的)第一部分

一,属性:

属性是OC2.0之后出来的新语法,用来代替setter和getter方法,使用属性可以快速创建setter以及getter方法的声明,setter和getter方法的实现,另外添加了对实例变量操作的安全处理(其安全是通过内存管理实现的)

setter 方法作用:为单一的实例变量重新赋值, 规范: (- 号方法)无返回值, 名字以set开头后面加上要设置的实例变量的名字,该方法有且只有一个参数,参数的类型和实例变量类型相同

getter 方法作用:获取某一单一变量的值, 规范: (- 号方法)有返回值,返回值类型与要获取的实例变量的类型相同,名字与要获取的实例变量的名字相同,无参数

 实例变量依托于对象存在,为对象开辟空间是根据实例变量的空间大小开辟的

1,属性的三大特性 (关于语义特性的具体用法此处不再详细叙述,下面会解说)

         第一大特性:

         (1),readonly:告诉编译器,属性在自动生成方法时,只会生成getter方法,不会生成setter方法

         (2),readwrite:告诉编译器,输出在自动生成方法时,既要生成getter方法,也要生成setter方,系统默认的读写特性

         第二大特性: 原子特性

         (1),atomic:原子特性,保证线程安全,内部做了安全处理(加锁与解锁)

         (2),nonatomic:非原子特性,不保证线程安全,因为对于getter和setter方法的使用比较频繁,在一段时间内可能要访问多次,使用atomic会非常消耗系统资源,降低程序的执行效率,使用nonatomic虽然不保证线程安全,但是使用一般情况下是安全的,因此对于原子特性通常使用nonatomic

         第三大特性:语义特性

         (1),assign:直接赋值,适用于基本数据类型,也可适用于对象类型,系统默认的语义特性

         (2),copy:适用于对象类型,并且要服从NSCopying协议的对象,会复制出一个新的对象,拥有新的对象所有权,(引用计数 + 1)(暂时这样理解内存管理会详细介绍),

         (3),retain:适用于对象类型,会造成对象的引用计数 + 1;

         2,属性的定义

         @property(关键字,用来定义属性) + 属性的特性 + 属性的类型 (和实例变量类型相同)+ 属性名 (和实例变量名相同);  其中@property在.h文件中只是自动声明setter和getter方法的声明

         3,在.m文件中

         @synthesize(关键字)  属性的实现部分,实现属性自动生成的setter和getter方法,如果在.m文件中通过@synthesize对属性进行合成,系统会自动合成,只不过此时系统默认的setter和getter方法内部操作的实例变量是_属性名,我们通常情况下在.m文件中有关getter和setter的方法都是什么都不写

         (1),如果指定的实例变量在.h文件里没有定义,系统会自动生成指定的实例变量,但是生成的实例变量是私有的,子类不可以直接访问,如果实例变量想让子类继承,则必须在.h文件中定义实例变量.如果属性的实现部分没有指定内部所要操作的实例变量时,系统会自动生成一个和属性名一样的实例变量

         (2),如果对于setter和getter方法我们已经实现了系统就不会再自动生成

         (3),如果在.m文件中通过@synthesize对属性进行合成,系统会自动合成,只不过此时系统默认的setter和getter方法内部操作的实例变量是_属性名

下面举个Person类的例子说明

 (1), 在.h文件中

@interface Person :NSObject

        //这里定义实例变量是位了让子类继承,如果不写,系统默认生成的是私有的实例变量,(当然如果没有子类这里完全可以不写)

        {

            NSString*_name; //姓名

            NSString *_sex;  //性别

            NSInteger _age; //年龄

            NSString *_job;//工作

        }

 //定义属性将name的语义特性声明为retain,sex的语义特性声明为copy,job的语义特性声明为assign(系统默认的时assign,这里可以不写)

@property (nonatomic,retain) NSString *name;@property (nonatomic, copy) NSString *sex;

@property (nonatomic) NSInteger age;

@property (nonatomic) NSString *_job;

@end

(2), 在.m文件中  (把不同特性的setter和getter方法的内部实现详细的写出来,以便清楚的了解系统内如生成的代码)

在实现方法之前首先说明,在实现setter和getter方法时,内部绝对不可以出现self.+属性名.因为这样写相当于自己调用自己,会形成死循环

1), 把name语义特性声明为retain时,setter和getter方法的内部实现

setter方法:

- (void)setName:(NSString *)name

{

    if (_name != name) {

        [_namerelease];

        _name = [name retain];

    }

}

getter方法:

- (NSString *)name

{

    return [[_nameretain] autorelease];

}

2),把性别sex语义特性声明为copy时,setter和getter方法的内部实现

setter方法:

- (void)setSex:(NSString *)sex

{

    if (_sex != sex) {

        [_sexrelease];

        _ sex = [sex copy];

    }

}

getter方法:

- (NSString *)sex

{

    return [[_sexretain] autorelease];

}

3),把job语义特性声明为assign时,setter和getter方法的内部实现

setter方法:

- (void)setJob:(NSString *)job

{

   _job = job)

}

getter方法:

- (NSString *)job

{

    return_job;

}

4), age默认的语义特性为assign时,setter和getter方法的内部实现

setter方法:

- (void)setAge:(NSInteger)age

{

   _age != age)

}

getter方法:

- (NSString *)age

{

    return_age;

}

这里这样写的原因下面内存管理介绍

二,

 (一),内存管理简介:

1,iOS应用程序出现Crash(闪退),90%以上的原因是内存问题。在一个拥有

         数十个甚至是上百个类的工程里,查找内存问题极其困难。了解内存常

         见问题,能帮我们减少出错几率。

2,内存问题体现在两个方面:内存溢出、野指针异常。了解内存管理,能帮我

         们提升程序性能,大大减少调试bug时间。

3,内存管理机制分为三种:

(1),垃圾回收(gc)

         垃圾回收:程序员只需要开辟内存空间,不需要用代码显示地释

         放,系统来判断哪些空间不再被使用,并回收这些内存空间,以便再

         次分配。整个回收的过程不需要写任何代码,由系统自动完成垃圾回

         收。Java开发中一直使用的就是垃圾回收技术      

 (2),MRC(Manual Reference Count)人工引用计数:

         内存的开辟和释放都由程序代码进行控制。相对垃圾回收来说,对内存

         的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较

         高,程序员要熟悉内存管理的机制

(3),ARCAuto Reference Count)自动引用计数:

         iOS 5.0的编译器特性,它允许用户只开辟空间,不用去释放空间。

         它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放

         的代码。

 4,对于iOS支持两种内存管理方式:ARC和MRC

         C语言中,使用malloc和free,进行堆内存的创建和释放。堆内

         存只有正在使用和销毁两种状态。实际开发中,可能会遇到,两个以上

         的指针使用同一块内存。C语言无法记录内存使用者的个数。

         而OC采用引用计数机制管理内存,当一个新的引用指向对象

         时,引用计数器就递增,当去掉个引用时,引用计数就递减,当

         引用计数到零时,该对象就会释放占有的资源

 (二),内存管理基本原则:

         如果对一个对象进行alloc,retain,copy之后,就拥有了该对象的使用权,就必须

         对该对象进行release或者autorelease.即(谁使用+1操作,谁就要进行-1操

         作)

1,将OC里只能利用以下五种方法对引用计数改变:

(1),alloc:(+号方法)(与dealloc对应) 开辟堆区的内存空间,将对象的引用计数由0 变 1(+ 1操作);

 (2),copy:(-号方法)  重新开辟空间与要拷贝的对象(即空间)开辟的空间大小一样,里面存储的内容也完全一样,只是地址不同,引用计数由0 到 1(+ 1操作,这里不是对原对象的引用计数 + 1,而是对新拷贝的对象+ 1);

(3),retain:(-号方法)与release对应使用对象的引用计数 + 1(操作后立即 + 1),

(4),release:(-号方法)与retain对应使用对象的引用计数 - 1(操作后立即 - 1),

(5),autorelease:(-号方法) 对象的引用计数 - 1(不会立即 – 1,会在未来的某一时刻引用计数 – 1),只要有对象使用autorelease操作,就必须有对应的自动释放池autoreleasePool{},自动释放池工作原理:它会将声明为autorelease的对象放入离它最近的自动释放池中,当自动释放池销毁时,会向池中的每个对象发送一个release消息,因此使用autorelease实质的-1操作不是autorelease进行的还是release执行的

2,retainCount 用来获取当前对象的引用计数(针对自定义的类,系统的类我们不需要了解,因为其内部做了好多操作),

3,dealloc: 回收空间(与alloc对应)当该类型的对象引用计数为0时, 系统会自动调用dealloc方法来回收空间,该方法不需要手动调用,

4,当对象的引用计数为变为0时,不能在访问该对象,即不要对该对象做任 何操作,如果继续操作就会出现野指针问题,这时可能会写到某行代码时突 然crash(即使是没有写任何与引用计数相关的代码),因为此时系统已经自动回收了指针变量指向的空间,该指责你变量已经没有使用被收回的空间的权限了,也就不能访问没有权限的对象.

5,查找系统因为野指针问题崩溃的时哪一行代码: 在菜单栏上点击Product ->Scheme ->Edit Scheme->选中Objective-c那行的Enable Zomible Object 和 Debugger下面的最后一行,重新运行,即可找到哪里出错了.

6, 当写完和引用计数相关的代码后程序立即crash,是因为系统被回收后又使用了引用计数 - 1有关的操作,这时应该将其删除

7,我们平时要养成随时在对象后面记录对象当前的引用计数,以减少出错的概率

8,验证对象空间是否被回收,只有查看该类的dealloc方法有没有执行即可

三,下面仍以Person为例具体介绍

setter和getter方法,内部是对实例变量赋值以及实例变量的取值操作,所有方法内部要操作实例变量

1,把name语义特性声明为retain时,setter和getter方法的内部实现

setter方法:

- (void)setName:(NSString *)name

{

    if (_name != name) {

        [_namerelease];

        _name = [name retain];

    }

}

getter方法:

- (NSString *)name

{

    return [[_nameretain] autorelease];

}

(1), if (_name != name)判断条件目的: 判断原有对象和新对象是否是同一个,如果是同一个就没必要重新赋值了,否则会先release, release后空间就被系统回收了,此时若再retain就会出现野指针问题

(2), [_namerelease]操作的目的: 释放保有的之前对象的所有权,若不释放会造成内存泄露,因为前一个对象已经不再使用了

(3), _name = [name retain]操作的目的: 让实例变量保有新的对象所有权,retain解决了野指针问题

2,把性别sex语义特性声明为copy时,setter和getter方法的内部实现

 setter方法:

- (void)setSex:(NSString *)sex

{

    if (_sex != sex) {

        [_sexrelease];

        _ sex = [sex copy];

    }

}

针对setter方法

(1), if (_sex != sex)判断条件目的: 判断原有对象和新对象是否是同一个,如果是同一个就没必要重新赋值了,否则会先release, release后空间就被系统回收了,此时若再retain就会出现野指针问题

(2), [_sexrelease];操作的目的: 释放保有的之前对象的所有权,若不释放会造成内存泄露,因为前一个对象已经不再使用了

 (3), _ sex = [sex copy];此处的copy操作跟上面的retain操作有所不同,copy是把sex指向的空间复制一份(即重新开辟一个空间,大小跟sex指向的空间大小一样,空间里存储的数据都相同),的操作的目的:让实例变量保有新的对象所有权,retain解决了野指针问题,

getter方法:

- (NSString *)sex

{

    return [[_sexretain] autorelease];

}

3,把job语义特性声明为assign时,setter和getter方法的内部实现

setter方法:

- (void)setJob:(NSString *)job

{

   _job = job)

}

 这里由于job的语义特性为assign,所以其内部的操作是直接赋值的方式

 getter方法:

- (NSString *)job

{

    return_job;

}

4, age默认的语义特性为assign时,setter和getter方法的内部实现

setter方法:

- (void)setAge:(NSInteger)age

{

   _age != age)

}

这里age为基本数据类型,为它开辟的空间是在栈区的,除了堆区需要手动管理,其他的内存区域都是系统管理,对基本数据类型系统默认的语义特性为assign, 所以其内部的操作也是是直接赋值的方式

getter方法:

- (NSString *)age

{

    return_age;

}

</span>

属性与内存管理(属性与内存管理都是相互关联的),布布扣,bubuko.com

时间: 2024-10-24 10:41:28

属性与内存管理(属性与内存管理都是相互关联的)的相关文章

linux内核探索之内存管理(二):linux系统中的内存组织--结点、内存域和页帧

本文主要参考<深入linux内核架构>(3.2节)及Linux3.18.3内核源码 概述:本文主要描述了内存管理相关的数据结构:结点pg_data_t.内存域struct zone以及页帧(物理页):struct page ,以及该结构相关的一些基本概念. 1. 概述 内存划分为接点,每个结点关联到系统中的一个处理器,在内核中表示为pg_data_t. 各个结点又划分为内存域,比如DMA内存域,高端内存域,普通内存域. 内核内存域的宏: enum zone_type { #ifdef CONF

java 内存管理 —— 《Hotspot内存管理白皮书》

说明   要学习Java或者任意一门技术,我觉得最好的是从官网的资料开始学习.官网所给出的资料总是最权威最知道来龙去脉的.而Java中间,垃圾回收与内存管理是Java中非常重要的一部分.<Hotspot内存管理白皮书>是了解Java垃圾收集器最权威的文档.相比于其他的一些所谓翻译文章,本文的翻译更加准确,通顺和全面.在翻译的过程中如果出现一些问题,如果出现问题或者表述不清楚的地方,可以直接在评论区评论. 1.简介    JavaTM 2 Platform, Standard Edition (

Python学习手册笔记——管理属性

管理属性有四种方式:1.__getattr__和__setattr__:把未定义的属性获取和所有的属性赋值指向通用的处理器方法. 2.__getattribute__:把所有的属性获取和赋值指向Python2.6中的新式类和Python 3.0中的所有类的中的一个处理器方法 3.property内置函数,把特定属性访问定位到get和set函数,也叫做特性 4.描述符:把特定属性访问定位到具有任意get和set函数的类的实例 特性 attribute = property(fget, fset,

内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现

http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好地理清系统编程和网络编程中的一些概念性问题,并没有深入地阅读分析源码,我也是草草翻过这本书,请有兴趣的朋友自己参考相关资料.此书出版较早,分析的版本为2.4.16,故出现的一些概念可能跟最新版本内核不同.

管理App的内存

https://developer.android.com/training/articles/memory.html#Android 对于任何软件来说RAM都是一个非常重要的资源,但是由于物理内存总是有限的,所以内存对于手机操作系统来说也更加重要.尽管Android的Dalvik虚拟机会执行GC,但是仍然不允许忽略应该在什么时候,什么地方分配和释放内存 为了垃圾回收器能够回收app的内存,需要避免内存泄露(通常是由全局变量持有对象引用引起)和在合适的时候释放引用的对象(如下面会说到的生命周期的

Java内存管理第二篇 - 内存的分配

Java内存管理无非就是对内存进行分配和释放.对于分配来说,基本类型和对象的引用存储到栈中,常量存储到常量池中,对象存储到堆上,这是一般的分配.而对于回收来说要复杂的多,如果回收不好,还可能造成分配出去的内存得不到回收而造成内存泄漏. 这一篇将简单介绍一下Java内存的分配,下一篇将介绍内存的回收及内存泄漏等知识. 1.JVM内存模型 1.程序计数器(Program Counter Register): 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是

Android Training - 管理应用的内存

http://hukai.me/android-training-managing_your_app_memory/ Random Access Memory(RAM)在任何软件开发环境中都是一个很宝贵的资源.这一点在物理内存通常很有限的移动操作系统上,显得尤为突出.尽管Android的Dalvik虚拟机扮演了常规的垃圾回收的角色,但这并不意味着你可以忽视app的内存分配与释放的时机与地点. 为了GC能够从app中及时回收内存,我们需要注意避免内存泄露(通常由于在全局成员变量中持有对象引用而导致

Linux-内存管理机制、内存监控、buffer/cache异同

在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,主要特点是,无论物理内存有多大,Linux 都将其充份利用,将一些程序调用过的硬盘数据读入内存(buffer/cache),利用内存读写的高速特性来提高Linux系统的数据访问性能.在这方面,区别于Windows的内存管理.本文从Linux的内存管理机制入手,简单介绍linux如何使用内存.监控内存,linux与windows内存管理上的区别简介,linux内

Python——管理属性(2)

__getattr__和__getattribute__ 目前已经介绍了特性property和描述符来管理特定属性[参考这里],而__getattr__和__getattribute__操作符重载方法提供了拦截类实例的属性获取的另一种方法,它们有更广泛的应用,可是它们的表现并不同: [1]__getattr__针对未定义的属性运行--也就是说,属性没有存储在实例上,或者没有从其类之一继承. [2]__getattribute__针对每个属性,因此,当使用它的时候,必须小心避免通过把属性访问传递给