2011-01-14 156 views
2

我是iPhone編程的新手。我在編程中沒有使用Interface Builder。我對內存管理有些疑問,iPhone中的@property主題。 考慮下面的代碼iPhone內存管理

@interface LoadFlag : UIViewController { 
    UIImage *flag; 
    UIImageView *preview; 

} 

@property (nonatomic, retain) UIImageView *preview; 
@property (nonatomic, retain) UIImage *flag; 

... 

@implementation LoadFlag 
@synthesize preview; 
@synthesize flag; 

- (void)viewDidLoad 
{ 
    flag = [UIImage imageNamed:@"myImage.png"]]; 
    NSLog(@"Preview: %d\n",[preview retainCount]); //Count: 0 but shouldn't it be 1 as I am retaining it in @property in interface file 
    preview=[[UIImageView alloc]init]; 
    NSLog(@"Count: %d\n",[preview retainCount]); //Count: 1 
    preview.frame=CGRectMake(0.0f, 0.0f, 100.0f, 100.0f); 
    preview.image = flag; 
    [self.view addSubview:preview]; 
    NSLog(@"Count: %d\n",[preview retainCount]); //Count: 2 
    [preview release]; 
    NSLog(@"Count: %d\n",[preview retainCount]); //Count: 1 
} 

... 
  1. 當&爲什麼(什麼是需要)我必須設置@property與保留(在UIImage & UIImageView上述情況)?我在很多示例程序中看到了這種說法,但並不瞭解它的必要性。

  2. 當我聲明@property (nonatomic, retain) UIImageView *preview;聲明時,保留計數爲0.爲什麼它不增加1,儘管它保留在@property中。

  3. 另外當我聲明[self.view addSubview:preview];然後再保留計數增量1。在這種情況下,「Autorelease pool」會在稍後發佈,否則我們必須注意釋放它。我不確定,但我認爲Autorelease應該處理它,因爲我們沒有明確保留它,所以我們爲什麼要擔心釋放它。

  4. 現在,[preview release];聲明後,我的數爲1。現在我並不在我的計劃需要UIImageView了,所以何時何地,我應該釋放使得計變爲0,內存被釋放。再次,我不確定,但我認爲Autorelease應該處理它,因爲我們沒有明確保留它,所以我們爲什麼應該擔心釋放它。如果我在-(void) dealloc中釋放它會發生什麼?

  5. 在聲明 - >flag = [UIImage imageNamed:@"myImage.png"]];我沒有分配任何內存來標記,但我怎麼能仍然在我的程序中使用它。在這種情況下,如果我不分配內存,那麼誰分配內存,或者是「標誌」,只是指向 - >[UIImage imageNamed:@"myImage.png"]];的引用。如果它只是一個參考,那麼我是否需要釋放它。

+3

第一個事實:不要信任RETAINCOUNT! – jv42 2011-01-14 12:44:57

+1

爲什麼不呢?誠然,不要爲此而煩惱,尤其是。具體的價值,但只要你沒有多個線程運行,訪問你的東西,你可以使用它作爲一個指標,如果你已經創建了泄漏。這是多重指標之一,這不一定是理想的指標。 – 2011-01-14 12:47:51

+1

不是; `retainCount`沒用,總會有更好的方法。總是。只要您通過任何系統API傳遞任何對象,保留計數就很可能會發生變化,通常無法查看源代碼的方式無法估計。 – bbum 2011-01-14 18:04:02

回答

1

問題1

這意味着合成的屬性訪問消息將包括當被稱爲所述消息(但只能被稱爲消息時,見下)的自動保留。

問題2

這是因爲您沒有使用屬性訪問的消息,你只是分配給成員變量。如果你使用:

self.preview = [[[UIImageView alloc] init] autorelease]; 

得到的保留計數將是一個(+1爲init,-1自動釋放,+1對消息的保留)。

N.B.

如果你這樣做你會得到相同的保留計數(之一)這樣的:

preview = [[UIImageView alloc] init]; 

(+1爲init,不使用屬性訪問消息,從而沒有多餘的保留)。由你決定。

問題3

的addSubview將再次遞增保留計數,因爲預覽將被存儲在一個集合將保留它的對象英寸

所以是的,基本上,如果您將對象移交給另一個對象進行管理(就像addSubview的情況一樣),您可以將其設置爲自動釋放,並由其他對象釋放。但是,由於您將UIImageVIew存儲在保留屬性中,因此您需要自行釋放它(請參閱下一頁)。

問題4

因爲你保持預覽對象保留的財產,你需要釋放你的dealloc消息。因此,在我的問題2示例中,您分配對象,autorelease它,但將其分配給保留屬性,所以保留計數畢竟將是一個,您將它添加到集合中,這也將保留它。清理視圖時,集合會減少保留計數,但您也需要調用釋放,因爲您將其存儲在保留屬性中。因此,在你的dealloc:

[preview release]; 

問題5

imageNamed是一個輔助消息不分配,初始化和自動釋放。所以基本上這相當於說。

NSData * dataForImage = get data from the myImage.png here ... 
self.flag = [[[UIImage alloc] initWithData:dataForImage] autorelease]; 

你正在一個保留的性質將其存儲(因爲我在上面的例子中使用self.flag),所以你需要釋放它的dealloc的消息。

1

當你寫

flag = [UIImage imageNamed:@"myImage.png"]]; 

你分配給實例變量直接,繞過屬性訪問。相反,您需要使用點符號:

self.flag = [UIImage imageNamed:@"myImage.png"]]; 

這解釋了您的保留計數問題。

我發現使用不同名稱聲明實例變量很有用,例如_flag對於屬性flag。通過書寫

@property .... flag = _flag; 

這樣你就不會意外地直接使用變量。如果有需要,你當然可以這樣做。

0
  1. 您使用retain來聲明對象的所有權。這基本上意味着,當屬性被賦值時,只要擁有的對象需要它,就確保它在那裏。

  2. @property ...是您的班級界面的聲明。這並不意味着有問題的財產價值,只是「LoadClass的實例有一個flag屬性,它由它保留」。直到你實際賦值給一個實例的屬性纔會保留。

  3. 這是因爲UIView聲明其子視圖的所有權。

  4. 您的對象可能不需要它,但UIView仍然需要它。

  5. 它由UIImage自動發佈。

您應該閱讀Apple的Memory Management的完整指南。我試圖將內存管理視爲擁有對象或不......它有幫助。

2

你說......

我是新手iPhone編程。我在 編程中沒有使用Interface Builder。

等等。什麼?爲什麼不? 不是使用IB作爲新環境的人通常表示您正在以艱難的方式執行您的應用程序。不使用IB進行應用程序開發是爲罕見的,通常相當先進的情況保留的。

0

問題2:@interface中的@property語句實際上只是編譯器的一個指令,用於爲具有指定特性的實例變量自動生成訪問器方法。運行代碼時@property不會導致任何操作發生。編譯器將查看@property行併爲您生成不可見的訪問器代碼。

@property (nonatomic, retain) UIImageView *preview; 

會導致編譯器生成這個樣子的存取方法:

- (void) setPreview:(UIImageView *)newValue { 
    [self willChangeValueForKey:@"preview"]; 
    if (preview != newValue) { 
    [preview release]; 
    preview = [newValue retain]; 
    } 
    [self didChangeValueForKey:@"preview"]; 
} 

- (UIImageView *) preview { 
    return preview; 
} 

@property是爲你節省時間;它指示編譯器爲您的變量生成訪問器代碼,這些代碼是高效但不可見的。如果您沒有使用@property,則必須在自定義類中編寫與上述類似的訪問器方法。