iOS 開發中,嘗試將 4 張圖片隨機分配給 4 個按鈕。代碼運行到 [images removeObjectsAtIndexes:randomIndex] 時報錯:Implicit Conversion of 'int' to 'NSIndexSet' is disallowed with ARC。
-(void)RandomButtonImage {
NSMutableArray *images = [NSMutableArray arrayWithObjects:
@"Character_1_1.png", @"Character_1_2.png",
@"Character_2_1.png", @"Character_2_2.png", nil];
NSArray *buttons = [NSArray arrayWithObjects:AnsButton1, AnsButton2, AnsButton3, AnsButton4, nil];
for (UIButton *btn in buttons) {
int randomIndex = random() % images.count;
UIImage *img = [images objectAtIndex:randomIndex];
[btn setImage:img forState:UIControlStateNormal];
[images removeObjectsAtIndexes:randomIndex]; // 錯誤:參數類型不匹配
}
}
removeObjectsAtIndexes: 接受 NSIndexSet* 參數,而非 int。ARC 環境下隱式轉換被禁止。NSString*(文件名),但直接賦值給 UIImage* 變量,需先用 [UIImage imageNamed:] 加載。random() % count 存在模數偏差,且每次從數組中刪除元素導致索引變化,但邏輯上可行。-(void)RandomButtonImage {
NSMutableArray *imageNames = [NSMutableArray arrayWithObjects:
@"Character_1_1.png", @"Character_1_2.png",
@"Character_2_1.png", @"Character_2_2.png", nil];
NSArray *buttons = @[AnsButton1, AnsButton2, AnsButton3, AnsButton4];
for (UIButton *btn in buttons) {
if (imageNames.count == 0) break;
NSUInteger randomIndex = arc4random_uniform((uint32_t)imageNames.count);
NSString *imageName = imageNames[randomIndex];
UIImage *img = [UIImage imageNamed:imageName]; // 關鍵:加載 UIImage
[btn setImage:img forState:UIControlStateNormal];
[imageNames removeObjectAtIndex:randomIndex]; // 正確方法:removeObjectAtIndex:
}
}
-(void)RandomButtonImage {
NSMutableArray *imageNames = [NSMutableArray arrayWithObjects:
@"Character_1_1.png", @"Character_1_2.png",
@"Character_2_1.png", @"Character_2_2.png", nil];
NSArray *buttons = @[AnsButton1, AnsButton2, AnsButton3, AnsButton4];
// Fisher-Yates 洗牌算法打亂數組
for (NSUInteger i = imageNames.count - 1; i > 0; i--) {
NSUInteger j = arc4random_uniform((uint32_t)(i + 1));
[imageNames exchangeObjectAtIndex:i withObjectAtIndex:j];
}
// 順序分配
for (NSUInteger i = 0; i < buttons.count; i++) {
if (i >= imageNames.count) break;
NSString *imageName = imageNames[i];
UIImage *img = [UIImage imageNamed:imageName];
[buttons[i] setImage:img forState:UIControlStateNormal];
}
}
優點:O(n) 時間複雜度、均勻隨機分布、無需重複生成隨機數與刪除操作。
NSMutableSet *usedIndices = [NSMutableSet set];
for (UIButton *btn in buttons) {
NSUInteger index;
do {
index = arc4random_uniform((uint32_t)imageNames.count);
} while ([usedIndices containsObject:@(index)]);
[usedIndices addObject:@(index)];
UIImage *img = [UIImage imageNamed:imageNames[index]];
[btn setImage:img forState:UIControlStateNormal];
}
| 問題 | 修正 |
|---|---|
removeObjectsAtIndexes: 接受 NSIndexSet | 改用 removeObjectAtIndex: 接受 NSUInteger |
| 字符串數組直接賦值給 UIImage | 使用 [UIImage imageNamed:] 加載圖片 |
random() % n 有模數偏差 | 使用 arc4random_uniform(n) 生成均勻隨機數 |
| 循環中刪除數組元素效率低 | 預先洗牌數組(Fisher-Yates),然後順序取用 |
Assets.xcassets 中管理,使用資源名稱而非文件名(避免 @2x/@3x 後綴問題)。@[] 字面量語法創建,類型安全且可讀性強。arc4random_uniform()(iOS/macOS)或 SecRandomCopyBytes()(加密級)。總結:隨機分配圖片到按鈕的核心問題是數組操作 API 誤用與字符串/UIImage 類型混淆。採用 Fisher-Yates 洗牌算法預先打亂圖片名稱數組,再順序分配給按鈕,是最高效、最穩健的解決方案。