2012-03-19 122 views
2

我想弄清楚合成myString到實例變量_myString的目的是什麼。iPhone實例變量問題

這樣做的目的是什麼?我傾向於注意到很多人這樣做。

另外我應該釋放實例變量並將實例變量設置爲零,是否正確。

ViewController.h

#import <UIKit/UIKit.h> 

@interface ViewController : UIViewController 
{ 
    NSString *_myString; 
} 

@property (nonatomic, retain) NSString *myString; 

@end 

ViewController.m

#import "ViewController.h" 

@implementation ViewController 

@synthesize myString = _myString; 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.myString = [[NSString alloc] initWithFormat:@"Hello"]; 

    _myString = [[NSString alloc] initWithFormat:@"Goodbye"]; 

    NSLog(@"%@\t%@", self.myString, _myString); 
} 

- (void)viewDidUnload 
{ 
    _myString = nil; 
    [super viewDidUnload]; 
} 

- (void)dealloc 
{ 
    [_myString release]; 
    [super dealloc]; 
} 

@end 
+0

就我們的聲望而言,你應該知道我們爲什麼要使用綜合......就我的觀點而言,綜合主要用於我們想要全局使用對象的時候(它也有另一個優點)..因爲我知道.. :) – Krunal 2012-03-19 13:58:13

+0

我知道它合成創建一個getter和setter爲什麼設置它等於實例變量? – Vikings 2012-03-19 14:05:05

+0

有一件事:你不應該在'viewDidUnload'中剔除'_myString',這個方法在'viewControllers'' view''被卸載並且與'myString'(或iVar'_myString')無關時調用。在'viewDidUnload'中,你應該省略掉連接到'.xib'的'IBOutlet'。 – 2012-03-19 14:07:05

回答

3

當您在目標c中合成一個對象類型屬性時,編譯器將爲該實例變量生成兩個隱藏方法。因此,當您參考myObject.myString時,不僅會返回_myString的指針,而且會調用生成的- (NSString*) myString方法。同樣,如果您將某些內容分配給該屬性:myObject.myString = @"foo";它將被編譯爲[myObject setMyString:@"foo"];

什麼是- (NSString*) myString- (void) setMyString:(NSString*) theString取決於您在聲明屬性時指定的關鍵字。最常見的是assign簡單爲您分配給指針:

- (void) setMyString:(NSString*) theString 
{ 
    _myString = theString; 
} 

- (NSString*) myString 
{ 
    return _myString; 
} 

這使得不聲明_myString公共變量太大的區別,但它是說,這個變量可以從外部直接訪問更明確的方式。

反過來,retain產生類似的setter方法(getter方法是相同的):

- (void) setMyString:(NSString*) theString 
{ 
    [theString retain]; 
    [_myString release]; 
    _myString = theString; 
} 

你可以看到,這需要你傳入的屬性的對象的內存管理的照顧。換句話說,您可以確定該物品在您的物業擁有它之前不會被釋放,因此在您擁有物品時您不必手動使用retain。這使編寫管理內存而不泄漏的代碼更方便。請注意,在dealloc中,您仍然必須向您的屬性應用nil才能釋放其存儲的最後一個對象。

數據不是來自實例變量,而是來自其他數據源(如數據庫)的另一類屬性。例如,Core Data的Managed Objects的自動生成的屬性就是如此。

最後,你也可以定義你自己的getters和setter。例如一個好主意,寫身邊的一些常用NSUserDefaults設置的屬性包裝,這將有利於它的訪問:

@interface Bar 

@property (nonatomic, assign) NSString* foo; 

@end 

@implementation Bar 

- (void) setFoo:(NSString *)theFoo 
{ 
    [[NSUserDefaults standardUserDefaults] setObject:theFoo 
               forKey:@"settings.foo"]; 
} 

- (NSString*) foo 
{ 
    return [[NSUserDefaults standardUserDefaults] 
     stringForKey:@"settings.foo"]; 
} 

@end 

myBar.foo = @"foobar"; // automatically persisted between application runs 

閱讀這些也:Advanced memory managementDeclared properties in objective C

+0

因此,在我的項目中,我應該使用_myString或self .myString?我猜self.myString。 – Vikings 2012-03-19 15:13:03

+1

是的,除了init和dealloc。這是詳細的原因:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW4 – MrTJ 2012-03-19 15:34:55

+0

非常感謝,清除了。 – Vikings 2012-03-19 21:54:14

1

self.myString(技術上[自的myString])的實際訪問和設置的ivar通過這樣寫此對象中的函數_myString這個:

-(NSString *)myString { 
    // code that is automatically generated by the @synthesize statement OR 
    // code that you write which over-rides the generated accessor. 
    // both of which generally return the value stored in _myString 
} 

-(void)setMyString:(NSString *)newString{ 
    // code that generally changes the value of _myString 
} 

使用_myString直接繞過這些func並直接訪問伊娃。

0

人們傾向於綜合屬性來強調前綴變量,而不是在編寫其他代碼時將兩者錯誤。例如:

// ... do sth 
myString = @"Foo"; 
// ... do sth else ... 
self.myString = @"Bar"; 

第一條指令直接訪問變量,第二條指令使用合成的setter。當你合成,而不指向特定的變量,然後爲屬性爲您創建的同名變量:

@synghesize myString; // this creates myString variable for you 

而不是這樣做,人們創造下劃線前綴變量,以避免錯誤地直接訪問它。當他們這樣做時,第一條指令myString = @"Foo"不再編譯,這使得當你繞開getter或setter錯誤時,很容易防止像那些令人討厭的錯誤。

至於你的第二個問題,如果可能的話使用ARC。如果沒有,你應該先釋放變量,然後重置指針。在你提交的代碼中,viewDidUnload將比dealloc調用的早,所以你將會有內存泄漏,因爲_myString在調用release之前會指向nil。