__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;
}
}
您應該在BWDB網站上發佈此問題。 – rmaddy
我做了,我也暫時修好了 – DaNY