1. MyClass.h
2.
3. @interface MyClass : NSObject {
4. MyObject *myObject;
5. }
6. @property (nonatomic, retain) MyObject *myObject;
7. @end
8.
9. MyClass.m
10.
11.
12. @synthesize myObject;
13.
14. -(id)init{
15. if(self = [super init]){
16. MyObject * aMyObject = [[MyObject alloc] init];
17. self.myObject = aMyObject;
18. [aMyObject release];
19. }
20. return self;
21. }
建立一個Student類,繼承NSObject類,代碼:
1. #import <Foundation/Foundation.h>
2.
3. @interface Student : NSObject{
4.
5. NSString *idd;
6. NSString *name;
7. }
8. @property (nonatomic, retain) NSString *idd;
9. @property (nonatomic, retain) NSString *name;
10.
11. @end
.m文件 代碼:
- #import "Student.h"
-
- @implementation Student
- @synthesize idd,name;
-
- - (void)dealloc
- {
- [idd release];
- [name release];
- [super dealloc];
- }
-
-
- @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文件 代碼:
- #import <Foundation/Foundation.h>
- @interface Student : NSObject{
-
- NSString *_idd;
- NSString *_name;
- }
- @property (nonatomic, retain) NSString *idd;
- @property (nonatomic, retain) NSString *name;
- @end
.m文件 代碼:
- #import "Student.h"
-
- @implementation Student
- @synthesize idd = _idd;
- @synthesize name = _name;
-
- - (void)dealloc
- {
- [_idd release];
- _idd = nil;
- [_name release];
- _name = nil;
- [super dealloc];
- }
- @end
能夠注意到上述代碼,與以前的代碼,在.h文件name變量改寫爲了_name;在.m文件中@sythesize的寫法也發生了變化。
若是經過方法self._name獲取屬性的值,xcode編譯器會提示錯誤,其實這也就說明了,咱們一般使用self.name實際使用的是student類name的get方法,同理name的set方法亦是如此。
有人就問, 爲何要這麼複雜的賦值? 爲何要加self. ? 直接寫成self.myObject = [[MyObject alloc] init];不是也沒有錯麼? 不加self有時好像也是正常的?
接下來從內存管理來講明使用self.和不使用self的區別
如今咱們來看看內存管理的內容:
ViewController.h文件,使用Student類,代碼以下:
- #import <UIKit/UIKit.h>
- @class Student;
-
- @interface ViewController : UIViewController{
-
- Student *_student;
- }
-
- @property (nonatomic, retain) Student *student;
-
- @end
ViewController.m文件,代碼:
- #import "ViewController.h"
- #import "Student.h"
-
- @implementation ViewController
- @synthesize student = _student;
-
- - (void)didReceiveMemoryWarning
- {
- [super didReceiveMemoryWarning];
- }
-
- #pragma mark - View lifecycle
-
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- }
-
- - (void) dealloc
- {
- [_student release];
- _student = nil;
- [super dealloc];
- }
其它的方法沒有使用到,因此這裏就不在顯示了。
在ViewController.m的viewDidLoad方法中建立一個Student類的對象
- Student *mystudent = [[Student alloc] init];
- self.student = mystudent;
- [mystudent release];
這是相信有人會有疑問了,問什麼建立student對象要這麼複雜,彷佛直接使用self.student = [[Student alloc] init]; 也沒有問題,不加self有時也是挺正常的呀?
接下來就須要從內存角度來分析它們之間的區別了:
先看間接賦值的:
1.加self.
- MyObject * aMyObject = [[MyObject alloc] init];
- self.myObject = aMyObject;
- [aMyObject release];
2. 不加self.
- MyObject * aMyObject = [[MyObject alloc] init];
- myObject = aMyObject;
- [aMyObject release];
再看直接賦值的:
3.加self.
- self.myObject = [[MyObject alloc] init];
4. 不加self.
- myObject = [[MyObject alloc] init];
如今是否是有點暈, 咱們先來把代碼改一下, 官方的一種常見寫法:
- MyClass.h
- @interface MyClass : NSObject {
- MyObject * _myObject;
- }
- @property (nonatomic, retain) MyObject *myObject;
- @end
- MyClass.m
- @synthesize myObject = _myObject;
OK, 你如今再試下, 若是你用self._myObject = aMyObject; 或者 myObject = aMyObject; 你會獲得一個錯誤, 爲何呢, 這裏就是和Obj-c的存取方法有關了. 說白了很簡單 , 你們都知道, @property (nonatomic, retain) MyObject *myObject; 是爲一個屬性設置存取方法, 只是平時咱們用的方法名和屬性名是同樣的,如今你把它寫成不一樣的名字, 就會很清楚了. _myObject是屬性自己, myObject是存取方法名.
如今咱們知道self.是訪問屬性的存取方法了, 那存取方法又怎麼工做的? self.myObject = [[MyObject alloc] init]; 爲何會有內存泄露?
關於nonatomic我很少解釋了, 它不是我要講的重點, 並且我也沒徹底搞清楚, 不誤導你們. 我只說assign, retain ,copy.
get方法是:
- -(MyObject*)myObject{
- return _myObject;
- }
Set方法是:
-
- -(void)setMyObject:(id)newValue{
- _myObject = newValue;
- }
-
- -(void)setMyObject:(id)newValue{
- if (_myObject != newValue) {
- [_myObject release];
- _myObject = [newValue retain];
- }
- }
-
- -(void)setMyObject:(id)newValue{
- if (_myObject != newValue) {
- [_myObject release];
- _myObject = [newValue copy];
- }
- }
其實這些方法裏還有別的內容, 並不僅是這些. 並且這些方法能夠被重寫. 好比你寫一個
- -(MyObject*)myObject{
- return _myObject;
- }
放在你的類裏, 你調用self.myObject時(不要把它放在等號左邊, 那會調用get方法)就會調用這個方法.
這裏多說一句, @property 是爲你設置存取方法, 和你的屬性無關, 你能夠只寫一句
- @property (readonly) NSString *name;
在你的類裏實現
- -(NSString*)name{
- NSLog(@"name");
- return @"MyClass";
- }
一樣能夠用self.name調用.
如今回頭說說咱們開始的那四個賦值, 當不用self.的時候, 那句話只是通常的賦值, 把一個指針賦給另外一個指針, 不會對分配的內存有任何影響, 因此2中不要最後[aMyObject release];這句話和4是一回事. 這裏就很少說了.咱們看看1和3,
當調用setMyObject:方法時, 對newValue 作了一次retain操做, 咱們必須把原來的newValue釋放掉, 否則就會內存泄露, 在1裏, 咱們有個aMyObject能夠用來釋放, 在3裏, 咱們沒法釋放它, 因此, 在3裏, 咱們會多出來一個retainCount. 內存泄露了.
說了這麼多, 我只想讓你們清楚, 什麼是調用屬性自己, 什麼是調用存取方法. 怎麼樣才能避免內存泄露, 並且, 以上例子裏是在本身類裏的調用, 若是這個類被別的類調用時, 更要注意一些,
順便說一下, 若是你想在其它類訪問對象屬性, 而不是經過存取方法, 你能夠用myClass -> myObject來訪問, 這樣是直接訪問對象自己, 不過你先要把myObject設成@public. 但這個是官方不提倡的,