You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中for循环创建卡片UIButton时生成数量与预期不符问题

问题:Swift记忆游戏卡片创建数量异常

我在使用Swift开发记忆类游戏,用户可以在菜单视图控制器选择游戏界面展示的卡片总数量,选择完成后该参数会被传递到游戏视图控制器。我通过for循环创建对应卡片的UIButton,每创建一个按钮就存入数组统一管理,但初始化游戏时会出现卡片显示数量不对的问题:选择8张卡片时能正常显示8个,选10张时只会显示9个。

相关代码

func createCardButtons(){
    
    let initialPos = Int(screenWidth/50)
    var xPos = Int(screenWidth/20)
    var yPos = Int(screenHeight/20)
    let size = Int(screenWidth/5)
    let cardBack = #imageLiteral(resourceName: "card_back")

    for _ in 0...cardsNum! {
        
        if xPos < Int(screenWidth - size) {
            
            let button = UIButton(frame: CGRect(x: xPos, y: yPos, width: size, height: size))
            button.addTarget(self, action: #selector(cardPressed), for: .touchUpInside)
            button.setImage(cardBack, for: .normal)
            view.addSubview(button)
            
            buttonsArr.append(button)
            
            xPos += size + initialPos
        } else {
            xPos = Int(screenWidth/20)
            yPos += size + initialPos
        }
    }
    
    print(buttonsArr)
}

控制台打印信息

  • 选择8张卡片时的打印结果:
[<UIButton: 0x157509950; frame = (18 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029dba60>>, 
 <UIButton: 0x157509c10; frame = (100 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029dae60>>, 
 <UIButton: 0x157509ed0; frame = (182 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029db960>>, 
 <UIButton: 0x15750a190; frame = (264 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029dacc0>>, 
 <UIButton: 0x15750a450; frame = (18 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029dbc20>>, 
 <UIButton: 0x15750a710; frame = (100 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029daca0>>, 
 <UIButton: 0x15750a9d0; frame = (182 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029dbb00>>, 
 <UIButton: 0x15750ac90; frame = (264 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029dbcc0>>]
  • 选择10张卡片时的打印结果:
[<UIButton: 0x15851ba30; frame = (18 40; 75 75); opaque = NO; layer = <CALayer: 0x600002057bc0>>, 
 <UIButton: 0x15851bcf0; frame = (100 40; 75 75); opaque = NO; layer = <CALayer: 0x600002043300>>, 
 <UIButton: 0x15851bfb0; frame = (182 40; 75 75); opaque = NO; layer = <CALayer: 0x60000204fba0>>, 
 <UIButton: 0x15851c270; frame = (264 40; 75 75); opaque = NO; layer = <CALayer: 0x60000204a340>>, 
 <UIButton: 0x15851c530; frame = (18 122; 75 75); opaque = NO; layer = <CALayer: 0x60000204a1a0>>, 
 <UIButton: 0x15851c7f0; frame = (100 122; 75 75); opaque = NO; layer = <CALayer: 0x60000206be80>>, 
 <UIButton: 0x15851cab0; frame = (182 122; 75 75); opaque = NO; layer = <CALayer: 0x600002061840>>, 
 <UIButton: 0x15851cd70; frame = (264 122; 75 75); opaque = NO; layer = <CALayer: 0x600002063a40>>, 
 <UIButton: 0x15851d030; frame = (18 204; 75 75); opaque = NO; layer = <CALayer: 0x600002063420>>]

问题原因

两个逻辑错误叠加,才会出现8张正常、10张少一个的现象:

  1. 循环区间写错
    Swift中0...cardsNum!是闭区间,会从0遍历到cardsNum,总执行次数是cardsNum + 1次,不是需要的cardsNum次。比如cardsNum=8时,循环实际跑9次。
  2. 换行逻辑空跑
    当x坐标超出当前行可容纳范围、进入else分支时,代码只重置了x坐标、累加了y坐标,没有在新行的这个位置创建按钮,这一次循环没有生成任何按钮,也不会往数组里加元素。

两个问题叠加后的实际效果:

  • cardsNum=8时,循环跑9次,其中1次刚好走到换行的else分支空跑,剩下8次正常创建按钮,刚好凑够8个,看起来"正常"。
  • cardsNum=10时,循环跑11次,其中2次走到换行的else分支空跑,剩下9次创建按钮,最终数组里只有9个元素,少1张卡片。

修复方法

  1. 把循环区间改成半开区间0..<cardsNum!,保证循环刚好执行cardsNum次。
  2. 换行重置坐标后,直接在新坐标位置创建按钮,不要让循环轮次空耗。

修复后的核心循环代码:

// 半开区间保证循环次数和卡片数一致
for _ in 0..<cardsNum! {
    if xPos < Int(screenWidth - size) {
        let button = UIButton(frame: CGRect(x: xPos, y: yPos, width: size, height: size))
        button.addTarget(self, action: #selector(cardPressed), for: .touchUpInside)
        button.setImage(cardBack, for: .normal)
        view.addSubview(button)
        buttonsArr.append(button)
        xPos += size + initialPos
    } else {
        // 换行重置坐标后直接创建按钮
        xPos = Int(screenWidth/20)
        yPos += size + initialPos
        
        let button = UIButton(frame: CGRect(x: xPos, y: yPos, width: size, height: size))
        button.addTarget(self, action: #selector(cardPressed), for: .touchUpInside)
        button.setImage(cardBack, for: .normal)
        view.addSubview(button)
        buttonsArr.append(button)
        xPos += size + initialPos
    }
}

如果觉得重复写创建按钮的代码太冗余,可以把创建按钮的逻辑抽成单独的方法,传入x、y坐标返回生成好的按钮,减少重复代码。


内容的提问来源于stack exchange,提问作者Matheus Farias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:54:18