2013-07-30 62 views
0

我在我的應用程序中使用Bill Weinman的BWDB的最新ARC版本,它的工作方式在Debug中很好。然而在發佈它崩潰。只有在真正的設備上,在模擬器中,它的工作原理很好。我試過Lynda.com最新的BWDB excersise文件,它也崩潰了。BWDB SQLLite包裝發佈錯誤

我發現該指針行已經發布,forin循環裏面,當你歷數結果

for (NSDictionary *firstSpecies in [sql getFirstSpeciesName]) 
{ 
    //firstSpecies is already released here 
    m_speciesName = [firstSpecies objectForKey:@"FirstSpeciesName"]; 
} 

這讓我相信有某種錯誤的執行

(NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len 

或enumRows變量。

你有什麼想法如何解決這個問題嗎?

+0

您應該在BWDB網站上發佈此問題。 – rmaddy

+0

我做了,我也暫時修好了 – DaNY

回答

0

__unsafe_unretained和__weak都會阻止對象的保留,但方式稍有不同。對於__weak,指向一個對象的指針將在它指向的對象的釋放時轉換爲零,這是非常安全的行爲。顧名思義,__unsafe_unretained將繼續指向對象所在的內存,即使它已被釋放。這可能會導致因訪問該已釋放對象而導致崩潰。

在BWDB例子有存儲到一個實例變量enumRows在枚舉函數行

- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len 
{ 
    if ((*enumRows = [self getPreparedRow])) 
    { 
    state->itemsPtr = enumRows; 
    state->state = 0; // not used, customarily set to zero 
    state->mutationsPtr = state->extra; // also not used, required by the interface 
    return 1; 
    } else { 
    return 0; 
    } 
} 

enumRows定義爲:

__unsafe_unretained NSDictionary * enumRows[1]; 

方法GetPreparedRow被聲明像這樣:

- (NSDictionary *) getPreparedRow 
{ 
int retCode = sqlite3_step(m_statement); 

if (retCode == SQLITE_DONE) 
{ 
    sqlite3_finalize(m_statement); 
    return nil; 
} 
else if (retCode == SQLITE_ROW) 
{ 
    int col_count = sqlite3_column_count(m_statement); 
    if (col_count >= 1) 
    { 
     NSMutableDictionary * dRow = [NSMutableDictionary dictionaryWithCapacity:1]; 
     for(int i = 0; i < col_count; i++) 
     { 
      NSString * columnName = [NSString stringWithUTF8String:sqlite3_column_name(m_statement, i)]; 
      [dRow setObject:[self columnValue:i] forKey:columnName]; 
     } 
     return dRow; 
    } 
} 
else 
{ 
    NSLog(@"rowFromPreparedQuery: could not get row: %s", sqlite3_errmsg(m_database)); 
    return nil; 
} 
return nil; 
} 

所以基本上NSDictiornay *這是從GetPreparedRow方法返回被存儲到__unsafe_unretained實例變量enumRows。 As GetPreparedRow已完成,NSDictionary *因爲超出範圍而被釋放,但enumRows仍然指向此內存。所以行可以枚舉,但每個當前行都指向無效的內存。

我不知道爲什麼這個工作在調試和發佈/模擬器,但它可能是momory不會被擦除或自動覆蓋向右走,所以enumRows仍然指向有效的內存。我寫信給Bill Weinman,他說這隻會發生在最新版本的LLVM編譯器上,而且只有最優化ON。如果您有興趣在修復它時收聽,請按照他的facebook page

同時我固定它在我的代碼通過使enumRows一個__strong所有權,簡單地定義爲:

NSDictionary * enumRows; 

,我改變了枚舉函數只是設置一個__unsafe_unretained指針指向這個__strong enumRows指針

- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len 
{ 
    if ((enumRows = [self getPreparedRow])) 
    { 
    __unsafe_unretained id row = enumRows; 
    state->itemsPtr = &row; 
    state->state = 0; // not used, customarily set to zero 
    state->mutationsPtr = state->extra; // also not used, required by the interface 
    return 1; 
    } else { 
    return 0; 
    } 
} 
1

比爾Weinman的BWDB得到更新的iOS 7,這也可以解決這個問題。

RSSDB.m

在IOS 7 SDK的一個錯誤防止這種上ARM工作

// for (row in [self getQuery:@"SELECT id FROM feed ORDER BY LOWER(title)"]) { 
//  [idList addObject:row[@"id"]]; 
// } 

解決方法爲iOS 7

[self prepareQuery:@"SELECT id FROM feed ORDER BY LOWER(title)"]; 
while ((row = [self getPreparedRow])) { 
    [idList addObject:row[@"id"]]; 
} 
+0

呵呵,你是救命恩人!!! –

0

@DaNY

如果我定義

NSDictionary * enumRows; 

然後

(NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len 
{ 
    if ((enumRows = [self getPreparedRow])) 
    { 
    __unsafe_unretained id row = enumRows; 
    state->itemsPtr = &row; 
... 

我得到1個警告和1個錯誤(編譯前):

兼容的指針類型初始化 '__unsafe_unretained' 類型的NSDictionary * __strong [1]

的」表達

不允許將間接指針隱式轉換爲Objective-C指針ARC