Swift Thread 1: Fatal error: init(coder:) has not been implemented (Calling super solution doesn't work)

巧了我就是萌 提交于 2019-12-01 11:03:00

问题


Hey guys I have searched all around and still cannot find a solution to my problem. I have a custom class here :

import UIKit

/** 
  DatasourceController is simply a UICollectionViewController that 
allows you to quickly create list views.

 In order to render our items in your list, simply provide it with a 
Datasource object.
 */
open class DatasourceController: UICollectionViewController, 
UICollectionViewDelegateFlowLayout {

open let activityIndicatorView: UIActivityIndicatorView = {
    let aiv = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
    aiv.hidesWhenStopped = true
    aiv.color = .black
    return aiv
}()

open var datasource: Datasource? {
    didSet {
        if let cellClasses = datasource?.cellClasses() {
            for cellClass in cellClasses {
                collectionView?.register(cellClass, forCellWithReuseIdentifier: NSStringFromClass(cellClass))
            }
        }

        if let headerClasses = datasource?.headerClasses() {
            for headerClass in headerClasses {
                collectionView?.register(headerClass, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(headerClass))
            }
        }

        if let footerClasses = datasource?.footerClasses() {
            for footerClass in footerClasses {
                collectionView?.register(footerClass, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: NSStringFromClass(footerClass))
            }
        }

        collectionView?.reloadData()
    }
}

public init() {
    super.init(collectionViewLayout: UICollectionViewFlowLayout())
}

required public init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

let defaultCellId = "lbta_defaultCellId"
let defaultFooterId = "lbta_defaultFooterId"
let defaultHeaderId = "lbta_defaultHeaderId"

override open func viewDidLoad() {
    super.viewDidLoad()
    collectionView?.backgroundColor = .white
    collectionView?.alwaysBounceVertical = true

    view.addSubview(activityIndicatorView)
    activityIndicatorView.anchorCenterXToSuperview()
    activityIndicatorView.anchorCenterYToSuperview()

    collectionView?.register(DefaultCell.self, forCellWithReuseIdentifier: defaultCellId)
    collectionView?.register(DefaultHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: defaultHeaderId)
    collectionView?.register(DefaultFooter.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: defaultFooterId)
}

override open func numberOfSections(in collectionView: UICollectionView) -> Int {
    return datasource?.numberOfSections() ?? 0
}

override open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return datasource?.numberOfItems(section) ?? 0
}

//need to override this otherwise size doesn't get called
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: view.frame.width, height: 50)
}

override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell: DatasourceCell

    if let cls = datasource?.cellClass(indexPath) {
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(cls), for: indexPath) as! DatasourceCell
    } else if let cellClasses = datasource?.cellClasses(), cellClasses.count > indexPath.section {
        let cls = cellClasses[indexPath.section]
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(cls), for: indexPath) as! DatasourceCell
    } else if let cls = datasource?.cellClasses().first {
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(cls), for: indexPath) as! DatasourceCell
    } else {
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: defaultCellId, for: indexPath) as! DatasourceCell
    }

    cell.controller = self
    cell.datasourceItem = datasource?.item(indexPath)
    return cell
}

override open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

    let reusableView: DatasourceCell

    if kind == UICollectionElementKindSectionHeader {
        if let classes = datasource?.headerClasses(), classes.count > indexPath.section {
            reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: NSStringFromClass(classes[indexPath.section]), for: indexPath) as! DatasourceCell
        } else if let cls = datasource?.headerClasses()?.first {
            reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: NSStringFromClass(cls), for: indexPath) as! DatasourceCell
        } else {
            reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: defaultHeaderId, for: indexPath) as! DatasourceCell
        }            
        reusableView.datasourceItem = datasource?.headerItem(indexPath.section)

    } else {
        if let classes = datasource?.footerClasses(), classes.count > indexPath.section {
            reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: NSStringFromClass(classes[indexPath.section]), for: indexPath) as! DatasourceCell
        } else if let cls = datasource?.footerClasses()?.first {
            reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: NSStringFromClass(cls), for: indexPath) as! DatasourceCell
        } else {
            reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: defaultFooterId, for: indexPath) as! DatasourceCell
        }
        reusableView.datasourceItem = datasource?.footerItem(indexPath.section)
    }

    reusableView.controller = self

    return reusableView
}

open func getRefreshControl() -> UIRefreshControl {
    let rc = UIRefreshControl()
    rc.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    return rc
}

@objc open func handleRefresh() {

}

open var layout: UICollectionViewFlowLayout? {
    get {
        return collectionViewLayout as? UICollectionViewFlowLayout
    }
}

}

Which is parent class to a UICollectionView controller in my storyboard. I make a controller class for it here :

import LBTAComponents

class homeView: DatasourceController {

override func viewDidLoad() {
    super.viewDidLoad()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

} 

Issue i get Thread 1: Fatal error: init(coder:) has not been implemented when running this code I have already tried the solution :

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

this does not work. Any other suggestions? I got this framework from cocoapod library if you would like to see for your self :

pod 'LBTAComponents'

I suspect the issue is something to do with a collection view and the storyboard but i cant figure it out.


回答1:


Whenever ViewController initialising form Storyboard/XIB, it doing it by init(coder: )

Your base class DatasourceController override initialisers

public init() {
    super.init(collectionViewLayout: UICollectionViewFlowLayout())
}

required public init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

So when you calling super.init(coder:...) in your HomeController, it will actually call fatalError("init(coder:) has not been implemented") Seems whoever wrote this class, is not a great storyboard/xib lover.

You can delete remove both initialisers in DatasourceController, but make sure that you setting up Flow layout in storyboard. Or you can change them to call super.

If you can't change base class, you can't load your VC from Storyboard.



来源:https://stackoverflow.com/questions/48192909/swift-thread-1-fatal-error-initcoder-has-not-been-implemented-calling-supe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!