總結一些Objective-C的self.用法

來源:互聯網
上載者:User

進入正題, 我們經常會在官方文檔裡看到這樣的代碼:

 
  1. MyClass.h 
  2.  
  3. @interface MyClass : NSObject { 
  4.     MyObject *myObject; 
  5. @property (nonatomic, retain) MyObject *myObject; 
  6. @end 
  7.  
  8. MyClass.m 
  9.  
  10.   
  11. @synthesize myObject; 
  12.   
  13. -(id)init{ 
  14.     if(self = [super init]){ 
  15.         MyObject * aMyObject = [[MyObject alloc] init]; 
  16.         self.myObject = aMyObject; 
  17.         [aMyObject release]; 
  18.     } 
  19.     return self; 

建立一個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檔案 代碼:

 
  1. #import "Student.h" 
  2.    
  3.   @implementation Student 
  4.   @synthesize idd,name; 
  5.     
  6.   - (void)dealloc 
  7.   { 
  8.       [idd release]; 
  9.       [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檔案 代碼:

 
  1. #import <Foundation/Foundation.h> 
  2. @interface Student : NSObject{ 
  3.   
  4.     NSString *_idd; 
  5.    NSString *_name; 
  6. @property (nonatomic, retain) NSString *idd; 
  7. @property (nonatomic, retain) NSString *name; 
  8. @end 

.m檔案 代碼:

 
  1. #import "Student.h" 
  2.   
  3. @implementation Student 
  4.  @synthesize idd = _idd; 
  5. @synthesize name = _name; 
  6.   
  7.  - (void)dealloc 
  8.  { 
  9.     [_idd release]; 
  10.     _idd = nil; 
  11.      [_name release]; 
  12.     _name = nil; 
  13.      [super dealloc]; 
  14.  } 
  15. @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類,代碼如下:

 
  1. #import <UIKit/UIKit.h> 
  2.  @class Student; 
  3.   
  4.  @interface ViewController : UIViewController{ 
  5.       
  6.     Student *_student; 
  7.  } 
  8.      
  9.   @property (nonatomic, retain) Student *student; 
  10.     
  11.  @end 

ViewController.m檔案,代碼:

 
  1. #import "ViewController.h" 
  2.  #import "Student.h" 
  3.     
  4.   @implementation ViewController 
  5.   @synthesize student = _student; 
  6.     
  7.   - (void)didReceiveMemoryWarning 
  8.   { 
  9.       [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. MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject retainCount = 1; 
  2. self.myObject = aMyObject; //myObject retainCount = 2; 
  3. [aMyObject release];//myObject retainCount = 1; 

2. 不加self.

 
  1. MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject retainCount = 1; 
  2. myObject = aMyObject; //myObject retainCount = 1; 
  3. [aMyObject release];//對象己經被釋放 

再看直接賦值的:

3.加self.

 
  1. self.myObject = [[MyObject alloc] init]; //myObject retainCount = 2; 

4. 不加self.

 
  1. myObject = [[MyObject alloc] init]; //myObject retainCount = 1; 

現在是不是有點暈, 我們先來把代碼改一下, 官方的一種常見寫法:

 
  1. MyClass.h 
  2. @interface MyClass : NSObject { 
  3.     MyObject * _myObject; 
  4. @property (nonatomic, retain) MyObject *myObject; 
  5. @end 
  6. MyClass.m 
  7. @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方法是:

 
  1. -(MyObject*)myObject{ 
  2.     return _myObject; 

Set方法是:

 
  1. // assign 
  2. -(void)setMyObject:(id)newValue{ 
  3.     _myObject = newValue; 
  4. // retain 
  5. -(void)setMyObject:(id)newValue{ 
  6.     if (_myObject != newValue) { 
  7.         [_myObject release]; 
  8.         _myObject = [newValue retain]; 
  9.     }  
  10. // copy 
  11. -(void)setMyObject:(id)newValue{ 
  12.     if (_myObject != newValue) { 
  13.         [_myObject release]; 
  14.         _myObject = [newValue copy]; 
  15.     } 

其實這些方法裡還有別的內容, 並不只是這些. 而且這些方法可以被重寫. 比如你寫一個

 
  1. -(MyObject*)myObject{ 
  2.     return _myObject; 

放在你的類裡, 你調用self.myObject時(不要把它放在等號左邊, 那會調用get方法)就會調用這個方法.

這裡多說一句, @property 是為你設定存取方法, 和你的屬性無關, 你可以唯寫一句

 
  1. @property (readonly) NSString *name; 

在你的類裡實現

 
  1. -(NSString*)name{ 
  2.     NSLog(@"name"); 
  3.     return @"MyClass"; 

同樣可以用self.name調用.

現在回頭說說我們開始的那四個賦值, 當不用self.的時候,  那句話只是一般的賦值, 把一個指標賦給另一個指標, 不會對分配的記憶體有任何影響, 所以2中不要最後[aMyObject release];這句話和4是一回事. 這裡就不多說了.我們看看1和3,

當調用setMyObject:方法時, 對newValue 做了一次retain操作, 我們必須把原來的newValue釋放掉, 不然就會記憶體泄露, 在1裡, 我們有個aMyObject可以用來釋放, 在3裡, 我們無法釋放它, 所以, 在3裡, 我們會多出來一個retainCount. 記憶體泄露了.

說了這麼多, 我只想讓大家清楚, 什麼是調用屬性本身, 什麼是調用存取方法. 怎麼樣才能避免記憶體泄露, 而且, 以上例子裡是在自己類裡的調用, 如果這個類被別的類調用時, 更要注意一些,

順便說一下, 如果你想在其它類訪問對象屬性, 而不是通過存取方法, 你可以用myClass -> myObject來訪問, 這樣是直接存取對象本身, 不過你先要把myObject設成@public. 但這個是官方不提倡的,

代碼比較簡單, 我還是發出來, 高人們可以忽略了.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.