首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS 隨機分配圖片到按鈕的數組操作修正

     編輯:程式設計綜合問答

問題現象

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]; // 錯誤:參數類型不匹配
    }
}

錯誤原因分析

  1. 方法參數類型錯誤:removeObjectsAtIndexes: 接受 NSIndexSet* 參數,而非 int。ARC 環境下隱式轉換被禁止。
  2. 圖片名稱與 UIImage 混淆:數組存儲的是 NSString*(文件名),但直接賦值給 UIImage* 變量,需先用 [UIImage imageNamed:] 加載。
  3. 隨機算法偏差: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) 時間複雜度、均勻隨機分布、無需重複生成隨機數與刪除操作。

方案三:使用 Set 確保不重複(若按鈕數 ≤ 圖片數)

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 洗牌算法預先打亂圖片名稱數組,再順序分配給按鈕,是最高效、最穩健的解決方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved