如何在UIView中初始化自定义参数?解决SampleSkinsCollectionView报错
解决UIView中自定义参数的初始化问题
错误原因分析
你遇到的两个Xcode错误本质是Swift初始化规则的约束:
- 'self' used in property access 'frame' before 'super.init' call:调用
super.init前self未完成初始化,不能访问self.frame属性 - Property 'self.currentMenuItem' not initialized at super.init call:
currentMenuItem是非可选存储属性,必须在调用父类初始化方法super.init前完成赋值
修正SampleSkinsCollectionView的初始化逻辑
调整初始化方法顺序,确保非可选存储属性在super.init前完成赋值,同时避免提前访问self:
import UIKit final class SampleSkinsCollectionView: UIView { // MARK: - Dependencies var handlerCellDelegate: IHandlerCellDelegate? var currentMenuItem: MenuItem // MARK: - Private properties private lazy var collectionCardMaps = createCollectionView() private var modelForDisplay: [SkinsModel] = [] // MARK: - Initializator // 主初始化方法:接收必要参数,frame设默认值 init(currentMenuItem: MenuItem, frame: CGRect = .zero) { // 先初始化自身非可选属性 self.currentMenuItem = currentMenuItem // 再调用父类初始化 super.init(frame: frame) // 初始化完成后执行配置逻辑 addUIView() setupConfiguration() setupLayout() } // 禁用系统默认frame初始化(如果只允许通过带currentMenuItem的方法创建) override init(frame: CGRect) { fatalError("Use init(currentMenuItem:frame:) instead") } // 便利初始化:同时传入代理和必要参数 convenience init(currentMenuItem: MenuItem, handlerCellDelegate: IHandlerCellDelegate?, frame: CGRect = .zero) { self.init(currentMenuItem: currentMenuItem, frame: frame) self.handlerCellDelegate = handlerCellDelegate } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Public methods func reloadModel(viewModel: [SkinsModel]) { self.modelForDisplay = viewModel collectionCardMaps.reloadData() } }
修正父视图控制器代码
创建SampleSkinsCollectionView时传入currentMenuItem:
final class MainSecondViewController: HeaderMenuViewController { // MARK: - Dependencies var iterator: IMainIterator? var handlerCardCellDelegate: IHandlerCellDelegate? // MARK: - Private properties private var currentMenuItem: MenuItem? // 延迟初始化,确保currentMenuItem赋值后再创建视图 private lazy var collectionCardSkins = SampleSkinsCollectionView( currentMenuItem: currentMenuItem!, handlerCellDelegate: self ) override init(delegate: IMenuDelegate, currentMenuItem: MenuItem) { super.init(delegate: delegate, currentMenuItem: currentMenuItem) self.currentMenuItem = currentMenuItem } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Public methods override func viewDidLoad() { super.viewDidLoad() setupConfiguration() addUIView() } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() setupLayout() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(true, animated: false) } } private extension MainSecondViewController { func setupConfiguration() { collectionCardSkins.translatesAutoresizingMaskIntoConstraints = false } }
关键注意点
- Swift初始化顺序:所有非可选存储属性必须在
super.init调用前完成初始化 - 避免提前访问self:
super.init完成前,不能访问self的任何属性或方法 - 统一初始化链:设计一个主初始化方法,其他初始化方法通过调用主方法实现逻辑复用
内容的提问来源于stack exchange,提问作者Steven Kirke
相关产品推荐
相关产品推荐

