2011-11-03 57 views
2

非常簡單的代碼,我可以說它在Xcode 4.1中按照預期工作,但在Xcode 4.2中中斷。下面是有問題的代碼:爲什麼當所有變量都可變時嘗試使用replaceOccurrencesOfString嘗試變更不可變對象:

-(void)mergeDevData2Email:(NSMutableString *)target codeArray:(NSArray *)array1 valueArray:(NSArray *)array2 { 
NSUInteger n = 0; 

for (NSMutableString *aCode in array1) { 
    if ([array2 count] > n) { 
     NSMutableString *arg = [array2 objectAtIndex:(NSUInteger)n]; 

     NSLog(@"Target isKindOf NSMutableString: %@", ([target isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO"); 
     NSLog(@"aCode isKindOf NSMutableString: %@", ([aCode isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO"); 
     NSLog(@"arg isKindOf NSMutableString: %@", ([arg isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO"); 

     [target replaceOccurrencesOfString:aCode withString:arg options:NSLiteralSearch range:NSMakeRange(0, [target length])]; 
     n++; 
    } 
    else { 
     break; 
    } 
} 
} 

這就是NSLogs顯示:

2011-11-03 15:42:59.967 TestProg [30413:C503]目標isKindOf的NSMutableString:YES

2011 -11-03 15:42:59.968 TestProg [30413:C503] ACODE isKindOf的NSMutableString:YES

2011-11-03 15:42:59.969 TestProg [30413:C503] ARG isKindOf的NSMutableString:YES

當我執行[target replaceOcurances ...行代碼我碰撞-

編程接收信號:「SIGABRT」。

隨着在控制檯日誌以下 -

2011-11-03 15:43:26.828 TestProg [30413:C503] *終止應用程序由於未捕獲的異常 'NSInvalidArgumentException',原因:「嘗試mutate與replaceOccurrencesOfString不可變的對象:withString:options:range:'

我的問題是,我在哪裏試圖改變一個不可變的對象?其次,爲什麼在Xcode 4.1中執行得很好?當然,所有玩家都看到了Xcode 4.1的可變性。 Xcode 4.2 有什麼區別?我在這裏錯過了一些微妙的東西。

+0

'isKindOfClass'將返回'YES',如果接收者是給定類或其任何類的實例,所以'[@「這是不可變的'isKindOfClass:[NSMutableString class]]'將返回'YES' 。 – wulong

回答

3

我懷疑有些字符串並不是真正可變的字符串(可能是「目標」,因爲這是您要修改的字符串)。這讓我很困惑,但「isKindOf:」並沒有區分可變字符串和不可變字符串。我相信你的NSLog查詢將返回YES,即使字符串不可變。

如果停在調試器中,您應該能夠檢查對象並確定它們是否確實是可變的(「真實」類名應該與對象一起顯示)。

至於爲什麼這工作在4.1而不是4.2,很難說。這可能是一些系統例程返回一個NSString用來返回一個NSMutableString,但不再。

如果我是正確的,你將需要去堆棧找出目標來自哪裏。在某些時候,它可能已經從NSString轉換爲NSMutableString。

+0

這是一個鏈接,備份我關於isKindOf的聲明:... http://stackoverflow.com/questions/1788690/objective-c-how-to-check-if-variable-is-nsarray-or-nsmutablearray – Ron

+0

那麼,我相信你是關於isKindOf的。和保羅一樣。但是我已經將目標反映的變量定義爲NSMutableString變量。它就是這樣......我很難理解如何按摩或替換代碼,以實現我想要的功能。有什麼建議麼 ?謝謝。 – Ric

+0

只需要檢查一下更多的東西......你說你將它定義爲一個NSMutableString,但它是從哪裏創建的?僅僅因爲某些東西被聲明爲NSMutableString並不意味着指針就是那個對象。編譯器應該能夠捕獲指針被誤判的情況,但這並不完美。你停在調試器中,看看「目標」對象是什麼樣子?調試器說它是什麼類?你知道實際創建該對象的代碼行嗎? – Ron

0

查閱Apple文檔isKindOfClass:

它基本上是說不要使用這種支票類集羣,並接着說

如果您調用返回一個類簇的方法,該方法返回的確切類型是最好的指標你可以用這個對象做什麼。

這是完全可能的,他們改變了在這個實例中SDK類之間從類集羣返回的類型。

0

在「target」中傳遞的變量被定義並用作NSMutableString的每個位置。一個地方的方法,之前所討論的方法中調用,變量是從文件的內容加載,並在該方法我,從缺乏經驗,使用的語句:

self.messageBody = fileContents; 

fileContents是一個NSString的。哎呀。

這顯然爲具有不同內存地址的messageBody創建了一個新的內存位置,並且不是可變的。問題 - 這是否實際上是一個新對象?如果是這樣,我猜它也會造成內存泄漏,因爲第一個實例不能再被釋放。

所以當我執行所討論的方法時,由「target」引用的對象不再是可變的,我的replaceOccurancesOfString語句崩潰了。

這並不回答爲什麼它在Xcode 4.1中執行所需的異常,但在Xcode 4.2中正確地崩潰。由於羅恩的建設性刺激,我找到了這個問題。 Thx給出。

+0

很高興你解決了你的問題!你也問過內存泄漏,可能你沒有泄漏內存。它取決於如何定義屬性「messageBody」,但是如果它是「保留」屬性,那麼當您分配給self.messageBody時,舊對象將「釋放」,並且新對象將「保留」。至於爲什麼它會在XCode4.1而不是XCode4.2中崩潰,這可能是因爲您在升級時更改了SDK。舊的SDK可能會返回一個真正是NSMutableString的NSString,所以你的代碼運氣好。在新的SDK中,它返回了導致崩潰的NSString。 – Ron

相關問題