IOS开发(49)之关于 self与内存相关的用法总结
今天新同事问了一些关于什么时候用全局变量,什么时候用self.赋值的问题,所以笔者在此说明一下。
何时使用self.在网上搜索或者里的回复大多都是简简单单的说这与objc的存取方法有关,如何与存取方式有关究竟他们之间的是什么样的关系就很少有同学回答了。下面以代码来说明问题:
创建一个student类,继承nsobject类,代码:
01 #import <foundation/foundation.h>
02
03 @ interface student : nsobject{
04
05 nsstring *idd;
06 nsstring *name;
07 }
08 @property (nonatomic, retain) nsstring *idd;
09 @property (nonatomic, retain) nsstring *name;
10
11 @end
.m文件 代码:
01 #import "student.h"
02
03 @implementation student
04 @synthesize idd,name;
05
06 - (void)dealloc
07 {
08 [idd release];
09 [name release];
10 [super dealloc];
11 }
12
13
14 @end
使用@propety @synthesize实现student的成员属性的set get方法。通常我们在其他类里访问student的成员属性的做法:
获取student的名字通过student.name,给名字赋值[student setname:@“jordy”]; 其中student是student类对象,如果在student类内部访问其成员属性使用[self setname:@”jordy”], 访问使用self.name;
注意:上述的代码,由于wordpress的原因,代码中的字符会自动保存为中文格式。你在使用时记得改为英文格式。
在student.h和student.m文件,是我们习惯性的写法,但似乎还是不能解释什么加self和不加self的区别,请看下面代码,是另一种习惯性的写法,还以student类为例:
.h文件 代码:
01 #import <foundation/foundation.h>
02
03 @ interface student : nsobject{
04
05 nsstring *_idd;
06 nsstring *_name;
07 }
08 @property (nonatomic, retain) nsstring *idd;
09 @property (nonatomic, retain) nsstring *name;
10
11 @end
.m文件 代码:
01 #import "student.h"
02
03 @implementation student
04 @synthesize idd = _idd;
05 @synthesize name = _name;
06
07 - (void)dealloc
08 {
09 [_idd release];
10 _idd = nil;
11 [_name release];
12 _name = nil;
13 [super dealloc];
14 }
15
16
17 @end
可以注意到上述代码,与之前的代码,在.h文件name变量改写为了_name;在.m文件中@sythesize的写法也发生了变化。
如果通过方法self._name获取属性的值,xcode编译器会提示错误,其实这也就说明了,我们通常使用self.name实际使用的是student类name的get方法,同理name的set方法亦是如此。
接下来从内存管理来说明使用self.和不使用self的区别:
viewcontroller.h文件,使用student类,代码如下:
01 #import <uikit/uikit.h>
02 @ class student;
03
04 @ interface viewcontroller : uiviewcontroller{
05
06 student *_student;
07 }
08
09 @property (nonatomic, retain) student *student;
10
11 @end
viewcontroller.m文件,代码:
01 #import "viewcontroller.h"
02 #import "student.h"
03
04 @implementation viewcontroller
05 @synthesize student = _student;
06
07 - (void)didreceivememorywarning
08 {
09 [super didreceivememorywarning];
10 }
11
12 #pragma mark - view lifecycle
13
14 - (void)viewdidload
15 {
16 [super viewdidload];
17 }
18
19 - (void) dealloc
20 {
21 [_student release];
22 _student = nil;
23 [super dealloc];
24 }
其它的方法没有使用到,所以这里就不在显示了。
在viewcontroller.m的viewdidload方法中创建一个student类的对象
1 student *mystudent = [[student alloc] init];
2 self.student = mystudent;
3 [mystudent release];
这是相信有人会有疑问了,问什么创建student对象要这么复杂,似乎直接使用self.student = [[student alloc] init]; 也没有问题,不加self有时也是挺正常的呀?
接下来就需要从内存角度来分析它们之间的区别了:
1、加self的方式:
1 student *mystudent = [[student alloc] init]; //mystudent 对象 retaincount = 1;
2 self.student = mystudent; //student 对象 retaincount = 2;
3 [mystudent release]; //student 对象 retaincount = 1;
retaincount指对象引用计数,student的property 是retain 默认使用self.student引用计数+1。
2、不加self的方式
1 student *mystudent = [[student alloc] init]; //mystudent 对象 retaincount = 1;
2 student = mystudent; //student 对象 retaincount = 1;
3 [mystudent release]; //student 对象内存已释放,如果调用,会有异常
3、加self直接赋值方式
1 self.student = [[student alloc] init]; //student 对象 retaincount = 2;容易造成内存泄露
由于objective-c内存管理是根据引用计数处理的,当一个对象的引用计数为零时,gcc才会释放该内存。