iOS类间传值问题:imageArray为空致崩溃如何修复?
问题修复:ModelView中imageArray为空导致数组越界崩溃
问题描述
在SampleViewController和ModelView之间传递index、pageIndex、imagesArray三个数据,期望SampleViewController加载完成时创建图片数组,并将数组与pageIndex传入ModelView的configure(theData: PageData)方法。但目前ModelView的imageArray为空,执行imageView.image = imageArray[pageIndex]时因数组越界崩溃。
崩溃原因分析
- 实例不匹配:代码中创建的
detailViewController是单独的ModelView实例,和页面上实际显示的pageViews数组中的ModelView实例完全无关,给detailViewController赋值imageArray不会作用到显示的视图上。 - 数据未同步:
loadImages的case 0分支仅将图片添加到本地images数组,但未赋值给SampleViewController的imageArray,也未同步给pageViews里的ModelView;case _分支虽然给imageArray添加了图片,但仅同步给detailViewController,而非显示用的pageViews。 - 调用configure时未传递必要数据:在
transitionAnimation中调用toView.configure前,没有给toView设置当前的pageIndex和imageArray。 - 语法错误: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
相关产品推荐
相关产品推荐

