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

Swift中切换SegmentedControl时阻止AdMob Banner重复加载

问题解决:避免AdMob Banner重复加载的正确姿势

首先,你当前的问题核心在于手动调用loadView()和viewDidLoad()——这两个是UIViewController的生命周期方法,本该由iOS系统自动调用,手动触发会导致整个视图层级被重新初始化,自然会让AdMob Banner跟着重复加载。我们需要换一种更合理的方式更新按钮,而不是重建整个视图。

具体修改步骤:

1. 抽离按钮创建逻辑为单独方法

把原来写在viewDidLoad里的按钮创建代码,提取成一个独立的方法,比如setupButtons()。这样我们可以在需要更新按钮时直接调用这个方法,而不用重建整个视图。

2. 修正AdMob Banner的创建逻辑

你当前的代码里,admobView是类的属性,但在viewDidLoad里又重新声明了一个局部变量var admobView = GADBannerView(),这会导致类属性没有被正确赋值,而且重复创建。我们要确保Banner只在viewDidLoad里创建一次,并且添加到视图上后不再重复操作。

3. 重写类别切换的处理方法

在handleButtonsChange里,更新currentArray后,先移除之前的所有按钮,再调用setupButtons()创建新按钮,完全不需要调用生命周期方法。

修改后的完整代码示例:

import UIKit
import AVFoundation
import GoogleMobileAds

class ViewController: UIViewController {
    var spaceForiPhoneX = 0
    var fontOfText = 9
    var admobView: GADBannerView!
    // true:测试
    let AdMobTest: Bool = true
    var player = AVAudioPlayer()
    var buttonArray: [UIButton] = [] // 改成非可选类型,初始化为空数组
    var currentArray: [String] = []
    var first = true
    
    override var prefersStatusBarHidden: Bool {
        return true
    }
    
    lazy var buttonSegmentedControl: UISegmentedControl = {
        let sc = UISegmentedControl(items: ["outou","outou2","bougen","meigen"])
        sc.translatesAutoresizingMaskIntoConstraints = false
        sc.tintColor = UIColor.white
        sc.selectedSegmentIndex = 0
        sc.addTarget(self, action: #selector(handleButtonsChange), for: .valueChanged)
        return sc
    }()
    
    @objc func handleButtonsChange() {
        switch buttonSegmentedControl.selectedSegmentIndex {
        case 0:
            currentArray = outou
        case 1:
            currentArray = outou2
        case 2:
            currentArray = bougen
        case 3:
            currentArray = meigen
        default:
            print("not selected")
        }
        // 移除旧按钮
        removeAllButtons()
        // 创建新按钮
        setupButtons()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if first {
            currentArray = reloadViewController.outou
            first = false
            print("Google Mobile Ads SDK version: \(GADRequest.sdkVersion())")
            
            // 初始化AdMob Banner,只做一次
            admobView = GADBannerView(adSize: kGADAdSizeBanner)
            admobView.frame.origin = CGPoint(x: 0, y: self.view.frame.size.height - admobView.frame.height + CGFloat(spaceForiPhoneX))
            admobView.frame.size = CGSize(width: self.view.frame.width, height: admobView.frame.height)
            admobView.adUnitID = TEST_ID
            admobView.rootViewController = self
            admobView.load(GADRequest())
            view.addSubview(admobView) // 这里应该添加到view上,而不是navigationItem.titleView?根据你的布局需求调整
        }
        
        view.backgroundColor = UIColor(r: 61, g: 91, b: 151)
        
        // 初始化按钮
        setupButtons()
        
        // 添加SegmentedControl并设置约束
        view.addSubview(buttonSegmentedControl)
        setupButtonSegmentedControl()
    }
    
    // 单独的按钮创建方法
    func setupButtons() {
        let numberOfrows = 6
        let numberOfLines = 3
        var count = 0
        let sizeOfButton = view.frame.height / 10
        let widthOfSpace = ((view.frame.width - sizeOfButton * 4) / 5 )
        
        for row in 0 ... numberOfrows {
            for line in 0 ... numberOfLines {
                guard count < currentArray.count else {
                    break
                }
                
                let button = UIButton(type: .custom)
                button.backgroundColor = UIColor(r: 1, g: 101, b: 161)
                button.setTitleColor(UIColor.white, for: .normal)
                button.titleLabel?.numberOfLines = 0
                button.setTitle(currentArray[row * 4 + line], for: .normal)
                button.frame = CGRect(x: (widthOfSpace + sizeOfButton) * CGFloat(line) + widthOfSpace, y: view.frame.height / 9.3 * CGFloat(row) + 50, width: sizeOfButton ,height: sizeOfButton )
                button.layer.cornerRadius = 10
                button.layer.borderColor = UIColor.white.cgColor
                button.layer.borderWidth = 1
                button.titleLabel?.font = UIFont.boldSystemFont(ofSize: CGFloat(fontOfText))
                button.tag = row * 4 + line
                button.addTarget(self, action: #selector(buttonPushed), for: .touchUpInside)
                button.showsTouchWhenHighlighted = true
                
                buttonArray.append(button)
                view.addSubview(button)
                
                count += 1
            }
        }
    }
    
    // 移除所有旧按钮的方法
    func removeAllButtons() {
        buttonArray.forEach { button in
            button.removeFromSuperview()
        }
        buttonArray.removeAll()
    }
    
    @objc func buttonPushed(button: UIButton) {
        guard let audioPath = Bundle.main.path(forResource: currentArray[button.tag], ofType: "mp3") else {
            print("音频文件不存在")
            return
        }
        do {
            try player = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath))
            player.play()
        } catch {
            print(error)
        }
    }
    
    func setupButtonSegmentedControl() {
        buttonSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        buttonSegmentedControl.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -90).isActive = true
        buttonSegmentedControl.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
        buttonSegmentedControl.heightAnchor.constraint(equalToConstant: 60).isActive = true
    }
}

关键说明:

  • 不再调用生命周期方法:handleButtonsChange里只负责更新数据源、移除旧按钮、创建新按钮,完全避免了视图重建。
  • Banner只初始化一次:AdMob的admobView在viewDidLoad里只创建并添加一次,后续切换类别不会再触碰它,自然不会重复加载。
  • 按钮管理更清晰:通过buttonArray保存所有按钮,移除时可以批量操作,避免内存泄漏和视图层级混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:19:10