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

iOS类间传值问题:imageArray为空致崩溃如何修复?

问题修复:ModelView中imageArray为空导致数组越界崩溃

问题描述

在SampleViewController和ModelView之间传递index、pageIndex、imagesArray三个数据,期望SampleViewController加载完成时创建图片数组,并将数组与pageIndex传入ModelView的configure(theData: PageData)方法。但目前ModelView的imageArray为空,执行imageView.image = imageArray[pageIndex]时因数组越界崩溃。

崩溃原因分析

  1. 实例不匹配:代码中创建的detailViewController是单独的ModelView实例,和页面上实际显示的pageViews数组中的ModelView实例完全无关,给detailViewController赋值imageArray不会作用到显示的视图上。
  2. 数据未同步:loadImages的case 0分支仅将图片添加到本地images数组,但未赋值给SampleViewController的imageArray,也未同步给pageViews里的ModelView;case _分支虽然给imageArray添加了图片,但仅同步给detailViewController,而非显示用的pageViews。
  3. 调用configure时未传递必要数据:在transitionAnimation中调用toView.configure前,没有给toView设置当前的pageIndex和imageArray。
  4. 语法错误:SampleViewController类顶层的detailViewController.pageIndex = pageIndex属于非法代码,类的顶层只能定义属性和方法,不能直接执行赋值语句。

修复步骤

  • 移除无用的detailViewController实例,所有操作针对pageViews中的两个ModelView实例。
  • 在loadImages方法完成图片加载后,将SampleViewController的imageArray同步给pageViews里的所有ModelView。
  • 在transitionAnimation中调用configure前,确保当前toView的pageIndex和imageArray是最新值。
  • 修复loadImages的case 0分支逻辑,将加载的图片存入SampleViewController的imageArray。
  • 在ModelView的configure方法中添加数组越界判断,避免崩溃。

修改后的代码

SampleViewController 修改版

class SampleViewController: UIViewController {
    
    var pagesData = [PageData]()
    var index = Int()
    var pageIndex: Int = -1
    var imageArray: [UIImage] = []
    let pageContainer: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    let pageViews: [ModelView] = {
        let view = [ModelView(), ModelView()]
        view[0].translatesAutoresizingMaskIntoConstraints = false
        view[1].translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
        
    override func viewDidLoad() {
        super.viewDidLoad()
        
        loadImages()
        // 加载完图片后同步给所有pageViews
        syncImageDataToPageViews()
        
        pageContainer.addSubview(pageViews[0])
        pageContainer.addSubview(pageViews[1])
        view.addSubview(pageContainer)

        transitionAnimation(animated: false, direction: "fromRight")
    }
        
    func setupViews() {
        pageContainer.addSubview(pageViews[0])
        pageContainer.addSubview(pageViews[1])
        view.addSubview(pageContainer)
    }
    
    func loadData(fileName: Any) -> PagesData {
        var url = NSURL()
        
        switch index {
        case 0:
            url = Bundle.main.url(forResource: "\(index)", withExtension: "json")! as NSURL
            
        case _:
            let fileManager = FileManager.default
            let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
            let documentDirectoryURL: NSURL = (urls.first as NSURL?)!
            url = documentDirectoryURL.appendingPathComponent("/\(index)/text.json")! as NSURL
        }
        
        let data = try! Data(contentsOf: url as URL)
        let person = try! JSONDecoder().decode(PagesData.self, from: data)
        return person
    }
    
    func loadImages() {
        imageArray.removeAll() // 先清空旧数据
        
        switch index {
        case 0:
            for imageIndex in 1...18 {
                if let image = UIImage(named: "\(imageIndex).jpg") {
                    imageArray.append(image)
                }
            }
            
        case _:
            let filemanager = FileManager.default
            let filesURL = URL.documentsDirectory.appendingPathComponent("\(index)")
            let numberOfJPGs = filemanager.enumerator(at: filesURL, includingPropertiesForKeys: nil)?
                .filter { ($0 as? URL)?.pathExtension.caseInsensitiveCompare("jpg") == .orderedSame }
                .count ?? 0
            
            for myIndex in 0..<numberOfJPGs { // 用..<避免越界,因为0...numberOfJPGs会包含numberOfJPGs索引,而数组是0到numberOfJPGs-1
                let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
                let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
                let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
                guard let dirPath = paths.first else { continue }
                let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("\(index)/images/\(myIndex).jpg")
                if let image = UIImage(contentsOfFile: imageURL.path) {
                    imageArray.append(image)
                }
            }
        }
    }
    
    // 同步imageArray和index到所有pageViews
    func syncImageDataToPageViews() {
        for view in pageViews {
            view.index = index
            view.imageArray = imageArray
        }
    }
        
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: view.self)
            if (location.x > self.view.frame.size.width - (view.safeAreaInsets.left * 1.5)) {
                transitionAnimation(animated: true, direction: "fromRight")
            } else if (location.x < (view.safeAreaInsets.left * 1.5)) {
                transitionAnimation(animated: true, direction: "fromLeft")
            }
        }
    }
    
    func transitionAnimation(animated: Bool, direction: String) {
        
        let result = loadData(fileName: pagesData)
        
        switch direction {
        case "fromRight":
            pageIndex += 1
        case "fromLeft":
            pageIndex -= 1
        default: break
        }
        
        if pageIndex <= -1 {
            pageIndex = 0
        } else if pageIndex >= result.pagesData.count {
            pageIndex = result.pagesData.count - 1
        } else {
            let fromView = pageViews[0].isHidden ? pageViews[1] : pageViews[0]
            let toView = pageViews[0].isHidden ? pageViews[0] : pageViews[1]
            
            // 给当前要显示的toView设置最新的pageIndex
            toView.pageIndex = pageIndex
            toView.configure(theData: result.pagesData[pageIndex])

            if animated {
                toView.isHidden = false
                UIView.animate(withDuration: 1.0, animations: {
                    let animation = CATransition()
                    animation.duration = 1.0
                    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
                    animation.isRemovedOnCompletion = true
                    animation.subtype = direction
                                        
                    let tapAnimationType = "fade"
                    switch tapAnimationType {
                    case "pageCurl": animation.type = "pageCurl"
                    case "fade": animation.type = "fade"
                    case "moveIn": animation.type = "moveIn"
                    case "push": animation.type = "push"
                    case "reveal": animation.type = "reveal"
                    default: animation.type = "fade"
                    }
                    
                    self.pageContainer.layer.add(animation, forKey: "pageAnimation")
                    self.pageContainer.bringSubview(toFront: toView)
                })
            } else {
                fromView.isHidden = true
                toView.isHidden = false
            }
        }
    }
}

ModelView 修改版

class ModelView: UIView {
    
    var textPosition = ""
    let textLabel = UILabel()
    let imageView = UIImageView()
    var index = Int()
    var pageIndex = Int()
    var imageArray: [UIImage] = []
        
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() {
        setupViews()
    }
        
    func setupViews() {
        addSubview(imageView)
        addSubview(textLabel)
    }
    
    func configure(theData: PageData) {
        textLabel.text = theData.textData
        textPosition = theData.textPosition
        textLabel.textColor = UIColor(theData.textColor)
        textLabel.layer.shadowColor = UIColor(theData.shadowColor).cgColor
        
        // 添加数组越界判断,避免崩溃
        guard pageIndex >= 0, pageIndex < imageArray.count else {
            imageView.image = nil // 或者设置默认图片
            return
        }
        imageView.image = imageArray[pageIndex]
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:17:33