70229


UITableVIewの中にUICollectionViewを入れたいのですが、  
`Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'UICollectionView must be initialized with a non-nil layout
parameter'`  
とエラーがでます。なぜでしょうか、また解決策はなんでしょうか。  
ご教授お願い致します。

現在のコード(全てコードで書いています)  
TableViewCell

[code]

    let width = UIScreen.main.bounds.width
    let height = UIScreen.main.bounds.height
    
    class TableCell: UITableViewCell {
        
        var collection = UICollectionView()
        
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.setup()
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override func prepareForReuse() {
            super.prepareForReuse()
        }
        
        override func layoutSubviews() {
            super.layoutSubviews()
            
            self.addSubview(collection)
        }
        
        func register(_ cellClass: AnyClass?,forCellReuseIdentifier identifier: String){
            
        }
        
        private func setup(){
            let layout = UICollectionViewFlowLayout()
            layout.itemSize = CGSize(width: width/3, height: width/3)
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            collection = UICollectionView(frame: CGRect(x: 0, y: 0, width: width, height: height), collectionViewLayout: layout)
            collection.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
            collection.backgroundColor = .white
            collection.dataSource = self
            collection.delegate = self
        }
    }
    
    extension TableCell: UICollectionViewDelegate, UICollectionViewDataSource{
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return 10
        }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
            cell.backgroundColor = .cyan
            return cell
        }
        
    }
    
[/code]

TableView

[code]

    class TableVC: UIViewController {
        
        var tableView = UITableView()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.setup()
            
        }
            
    }
    
    extension TableVC: UITableViewDelegate, UITableViewDataSource{
        
        func numberOfSections(in tableView: UITableView) -> Int {
            return 2
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
                let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! TableCell
                
                return cell
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
    
        }
        
        
    }
    
    extension ProfileVC{
        
        private func setup(){
            self.navigationItem.title = "www"
            
            self.setupTableView()
            self.view.addSubview(tableView)
        }
        
        private func setupTableView(){
            tableView = UITableView(frame: self.view.frame, style: .plain)
            tableView.register(TableCell.classForCoder(), forCellReuseIdentifier: "TableCell")
            tableView.delegate = self
            tableView.dataSource = self
            tableView.tableFooterView = UIView()
            tableView.separatorStyle = .none
            tableView.allowsSelection = false
               
           }
    }
    
[/code]


CC BY-SA 4.0
2020-09-08T09:40:45.763
70224
2020-09-08T11:17:50.403
36055
question
swift ios swift4 swift5
UITableViewの中にUICollectionViewを入れたいのですが、エラーがでてできません


あなたのコードの中で致命的な問題があるのはこの行です。

TableViewCell

[code]

        var collection = UICollectionView()
    
[/code]

エラーメッセージの`'UICollectionView must be initialized with a non-nil layout
parameter'`と言うのは、「`UICollectionView`を初期化するときには、非nilの layout
パラメータを指定しないといけない」と言っています。

ところがあなたは上に挙げた行で`UICollectionView()`なんて形で、layout
パラメータを持たないイニシャライザを呼んでしまっています。アウトです。

一般的にiOSのUIKit中の多くのクラスでは、引数を持たないイニシャライザの動作は未定義です。できるだけ使わないようにして、各クラスのドキュメントに定義されたイニシャライザのうちのどれかを使うようにした方が良いでしょう。

* * *

また、「致命的」と言えるほどの影響はすぐには出ないかもしれませんが、`layoutSubviews()`にも問題があります。

[code]

        override func layoutSubviews() {
            super.layoutSubviews()
            
            self.addSubview(collection) //<-
        }
    
[/code]

`layoutSubviews()`はiOSが子ビューのレイアウトを再計算する必要があると認めた場合に任意のタイミングで何度も呼ばれます。原則として、その中で`addSubview(_:)`のようにviewの階層構造を変えてしまうような操作を行なってはいけません。

これはあなたのコードであれば、`setup()`の中で行うのが適当でしょう。

* * *

と言うわけで、上記の2点を`TableCell`クラスに反映すると以下のようになります。

[code]

    class TableCell: UITableViewCell {
        
        var collection: UICollectionView! //<-
        
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.setup()
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override func prepareForReuse() {
            super.prepareForReuse()
        }
        
        override func layoutSubviews() {
            super.layoutSubviews()
            
            //self.addSubview(collection) //<- この行は削除する
        }
        
        func register(_ cellClass: AnyClass?,forCellReuseIdentifier identifier: String){
            
        }
        
        private func setup() {
            let layout = UICollectionViewFlowLayout()
            layout.itemSize = CGSize(width: width/3, height: width/3)
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            collection = UICollectionView(frame: CGRect(x: 0, y: 0, width: width, height: height), collectionViewLayout: layout)
            collection.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
            collection.backgroundColor = .white
            collection.dataSource = self
            collection.delegate = self
            
            self.addSubview(collection) //<-
        }
    }
    
[/code]

今後まだまだいじらないと所望の表示にはできなさそうなコードですが、少なくともこの修正で、`'UICollectionView must be
initialized with a non-nil layout parameter'`の実行時エラーは出なくなるはずです。


CC BY-SA 4.0
2020-09-08T11:17:50.403
70229
2020-09-08T11:17:50.403
13972
70224
answer