问题
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