簡體   English   中英

為什么發布我的數據會讓我的應用崩潰?

[英]Why does releasing my array crash my app?

如果我將第一個數組復制到第二個數組后發布我的應用程序崩潰。 如果我自動釋放第一個陣列一切正常。 為什么? 有沒有更好的方法將第一個數組復制到第二個數組?

如果我調用此方法,我得到一個ECX_BAD_ACCESS,我傳遞一個空數組

-(NSArray *)loadSystemDetails
{
    AssortedCodeSnippets *acs = [[AssortedCodeSnippets alloc] init];
    NSArray *details;
    NSString *fp = [self tempPathAndFileName:[self systemDetailsFileName]];
    if ([acs fileExistsAtPath:fp]) {
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:fp];
        details = array;
        [array release];
    } else {
        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release];
        [self saveDataFile:details toPath:fp];
    }
    NSLog(@"details: %@",details);
    [acs release];
    return details;
}

如果我自動釋放陣列它工作正常。

-(NSArray *)loadSystemDetails
{
    AssortedCodeSnippets *acs = [[AssortedCodeSnippets alloc] init];
    NSArray *details;
    NSString *fp = [self tempPathAndFileName:[self systemDetailsFileName]];
    if ([acs fileExistsAtPath:fp]) {
        NSArray *array = [[[NSArray alloc] initWithContentsOfFile:fp]autorelease];
        details = array;
    } else {
        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release];
        [self saveDataFile:details toPath:fp];
    }

讓我們一步一步

密鑰:M =釋放/保留消息,C =釋放/保留消息的總和

                                                              // +----+---+
                                                              // | M  | C |
                                                              // +----+---+
NSArray *array = [[NSArray alloc] initWithContentsOfFile:fp]; // | +1 | 1 |
details = array;                                              // |  0 | 1 |
[array release];                                              // | -1 | 0 |
                                                              // +----+---+

此時您可以看到您將返回計數為0的details ,因此已經取消分配=崩潰。

復制是錯誤的術語,因為您實際上並不需要副本,因此您只希望指針details指向有效對象,因此以下內容會更正確

- (NSArray *)systemDetails
{
    NSString *filePath = [self tempPathAndFileName:[self systemDetailsFileName]];

    NSArray *details = [[[NSArray alloc] initWithContentsOfFile:filePath] autorelease];

    if (!details) {

        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release]; cls = nil;
        [self saveDataFile:details toPath:filePath];

    }

    NSLog(@"details: %@",details);

    return details;
}

在這里,我正在利用NSArray的方法

initWithContentsOfFile:

... [return]如果無法打開文件或文件內容無法解析為數組,則為nil

這減少了一些殘余並使該方法更容易閱讀。 我還將變量名稱擴展為有意義的名稱(個人偏好)。

我還重命名了方法,因為load藝術是超級的,因為基本上你正在返回系統細節,它們被加載的事實並不是方法調用者真正關心的事實。

同樣重要的是要注意,其他答案建議您進行額外的保留/復制,然后記得稍后發布返回的結果。 這違反了cocoa約定,因為方法名稱不包含new / init / copy,因此方法的調用者不應該最終擁有結果。

發送details信息時分配retain消息,分配指向array detailscls-loadData方法的結果。 請務必在-loadSystemDetails方法之后的某處release details

在您的代碼示例中,您實際上並未將array復制到details 請記住,這兩個變量都是指向數組的指針 ,而不是數組本身。 因此,line details = array只是將array的位置復制到details 換句話說,在這一行之后,兩個變量都指向內存中完全相同的數組。 因此,當你調用release ,在內存中的對象被釋放,並且兩個 detailsarray正在指向一個不存在的對象。 如果要將數組實際復制到內存中,請使用

details = [array copy]

請記住,當你想要擺脫這個對象時,最終你必須在details上調用release

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM