从 CollectionViewCell 呈现视图时,调用中缺少参数 'coder' 的参数
Missing argument for parameter 'coder' in call when presenting a view from CollectionViewCell
我有一个 ViewController,里面有一个 CollectionView,还有一个 CollectionViewCell,里面有一个 TableView。当用户单击 TableViewCell 时,我想显示一个 ViewController 显示用户任务的详细视图,但我在这一行 let vc = MyTasksDetailController()
.
这是我的代码:
ProfileController
final class ProfileController: UIViewController {
private var collectionView: UICollectionView?
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
layout.sectionInset = UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 1)
let size = (view.width - 4)/3
layout.itemSize = CGSize(width: size, height: size)
collectionView = UICollectionView(frame: .zero,
collectionViewLayout: layout)
// Headers
collectionView?.register(ProfileInfoHeader.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: ProfileInfoHeader.identifier)
collectionView?.register(MyTasksCollectionCell.self,
forCellWithReuseIdentifier: MyTasksCollectionCell.identifier)
collectionView?.delegate = self
collectionView?.dataSource = self
guard let collectionView = collectionView else {
return
}
view.addSubview(collectionView)
}
extension ProfileController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyTasksCollectionCell.identifier,
for: indexPath)as! MyTasksCollectionCell
return cell
}
MyTaskCollectionCell
class MyTasksCollectionCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let task = {() -> Add in
switch (displayedTask) {
case .current:
// First segment tapped
return self.tasks[indexPath.row]
case past:
// Second segment tapped
return self.pastTasks[indexPath.row]
}
}()
let vc = MyTasksDetailController() //ERROR HERE: Missing argument for parameter 'coder' in call : Insert 'coder: <#NSCoder#>'
self.present(vc, animated: true, completion: nil)
}
MyTaskTableCell
class MyPostsTableCell: UITableViewCell {
var setdescriptionTitleLabel: String? {
didSet {
descriptionTitleLabel.text = setdescriptionTitleLabel ?? ""
}
}
var setdateLabel: String? {
didSet {
dateLabel.text = setdateLabel ?? ""
}
}
var sethourLabel: String? {
didSet {
hourLabel.text = sethourLabel ?? ""
}
}
var setDateIcon: UIImage? {
didSet {
dateIcon.image = UIImage()
}
}
var setHourIcon: UIImage? {
didSet {
hourIcon.image = UIImage()
}
}
MyTasksDetailController
class MyTasksDetailController: UIViewController {
internal var task: Add? {
didSet {
if let task = task {
setDescriptionLabel = task.description
setDescriptionTitleLabel = task.descriptionTitle
}
}
}
var setDescriptionLabel: String? {
didSet {
descriptionLabel.text = setDescriptionLabel ?? ""
}
}
var setdescriptionTitleLabel: String? {
didSet {
descriptionTitleLabel.text = setdescriptionTitleLabel ?? ""
}
}
let descriptionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 28, weight: .bold)
label.textAlignment = .center
return label
}()
let descriptionTitleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 18, weight: .bold)
label.textAlignment = .center
label.numberOfLines = 3
return label
}()
let container: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.clipsToBounds = true
v.backgroundColor = .white
v.layer.cornerRadius = 24
v.backgroundColor =
// 1
UIColor { traitCollection in
// 2
switch traitCollection.userInterfaceStyle {
case .dark:
// 3
v.layer.borderColor = UIColor.label.cgColor
return UIColor.systemBackground
default:
// 4
v.layer.borderColor = UIColor.black.cgColor
return UIColor.systemBackground
}
}
return v
}()
lazy var stackContainer: UIStackView = {
let stackContainer = UIStackView(arrangedSubviews: [stackDesLabel, stackDesTitLabel])
stackContainer.translatesAutoresizingMaskIntoConstraints = false
stackContainer.axis = .vertical
stackContainer.distribution = UIStackView.Distribution.fillEqually
return stackContainer
}()
lazy var stackDesLabel: UIStackView = {
let stackDesLabel = UIStackView(arrangedSubviews: [descriptionLabel])
stackDesLabel.translatesAutoresizingMaskIntoConstraints = false
stackDesLabel.axis = .vertical
stackDesLabel.distribution = UIStackView.Distribution.fillProportionally
return stackDesLabel
}()
lazy var stackDesTitLabel: UIStackView = {
let stackDesTitLabel = UIStackView(arrangedSubviews: [descriptionTitleLabel])
stackDesTitLabel.translatesAutoresizingMaskIntoConstraints = false
stackDesTitLabel.axis = .horizontal
stackDesTitLabel.distribution = UIStackView.Distribution.fillEqually
return stackDesTitLabel
}()
override func viewDidLoad() {
view.addSubview(stackDesLabel)
view.addSubview(stackDesTitLabel)
stackContainer.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
stackContainer.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
stackContainer.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
stackContainer.centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
stackContainer.heightAnchor.constraint(equalTo: container.heightAnchor).isActive = true
stackContainer.widthAnchor.constraint(equalTo: container.widthAnchor).isActive = true
stackDesTitLabel.topAnchor.constraint(equalTo: stackContainer.topAnchor, constant: 50).isActive = true
stackDesTitLabel.widthAnchor.constraint(equalTo: stackContainer.widthAnchor).isActive = true
stackDesTitLabel.centerXAnchor.constraint(equalTo: stackContainer.centerXAnchor).isActive = true
stackDesLabel.topAnchor.constraint(equalTo: stackDesTitLabel.bottomAnchor, constant: 50).isActive = true
stackDesLabel.leadingAnchor.constraint(equalTo: stackContainer.leadingAnchor, constant: 5).isActive = true
stackDesLabel.widthAnchor.constraint(equalTo: stackContainer.widthAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
添加(数据结构)
struct Add {
static var details: Add = Add()
var descriptionTitle: String = ""
var description: String = ""
var id: String?
var date: String = ""
var hour: String = ""
func getDict() -> [String: Any] {
let dict = [
"descriptionTitle": self.descriptionTitle,
"description": self.description,
"date": self.date,
"hour": self.hour,
] as [String : Any]
return dict
}
}
正如我所怀疑的那样,问题出在 MyTasksDetailController
与您实施
required init?(coder aDecoder: NSCoder)
如果您只是想要一个快速的解决方案,您可以根据对您的应用程序最有意义的事情做以下两件事之一:
- 删除
required init?(coder aDecoder: NSCoder)
- 像这样添加你自己的初始化器:
init() {
// Keep nil if you are not initializing from XIB
super.init(nibName: nil, bundle: nil)
}
说明
我相信您试图实现的目标违反了初始化继承规则,这就是您收到该错误的原因。
我正在查看全部rules from here。
当您这样做时:class MyTasksDetailController: UIViewController
- 如果您遵循以下规则,您将自动从 UIViewController 继承初始化程序:
自动初始化程序继承
Rule 1
If your subclass doesn’t define any designated initializers, it
automatically inherits all of its superclass designated initializers.
Rule 2
If your subclass provides an implementation of all of its
superclass designated initializers—either by inheriting them as per
rule 1, or by providing a custom implementation as part of its
definition—then it automatically inherits all of the superclass
convenience initializers.
These rules apply even if your subclass adds
further convenience initializers.
现在当您添加:
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
它违反了规则 1,您正在添加自己的指定初始化程序,因此您丢失了之前继承的所有其他初始化程序,因此您会收到此错误:
所以现在您有 2 个选项,如前所述。
1.删除 required init?(coder aDecoder: NSCoder)
如果您在情节提要中创建视图控制器,则需要此版本的 init,因为在这种情况下会自动调用它。如果您不打算这样做,您可以将其删除。如果你打算在故事板中使用它,你需要完成它:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
2。添加您自己的指定初始化器
通过添加 required init?(coder aDecoder: NSCoder)
,您丢失了之前继承的默认初始化程序,因此现在您需要创建自己的初始化程序:
init() {
// Initialize your local vars
// Call designated initializer from the super class
// Keep nil if you are not initializing from XIB
super.init(nibName: nil, bundle: nil)
}
以下任一方法都可以解决您的问题:
更新最后的想法
- 以上应该可以解决您的初始化错误
- 但是,你会在下一行出错
self.present(vc, animated: true, completion: nil)
简而言之,present
(documentation reference)只能被视图控制器调用
在您的代码中 MyTasksCollectionCell
是一个 UICollectionViewCell,因此您需要通知视图控制器您的集合视图位于其中,一个单元格被点击并且视图控制器需要处理呈现新视图。
您可以通过两种方式做到这一点:
- Delegates - 让您的视图控制器负责处理单元格点击并呈现另一个视图控制器
- Observers - 通知您的视图控制器处理单元格点击并呈现另一个视图控制器
这两个都会
这些只是给您一个想法的快速链接,但我建议您多用谷歌搜索一下,看看哪个最适合您的情况
我有一个 ViewController,里面有一个 CollectionView,还有一个 CollectionViewCell,里面有一个 TableView。当用户单击 TableViewCell 时,我想显示一个 ViewController 显示用户任务的详细视图,但我在这一行 let vc = MyTasksDetailController()
.
这是我的代码:
ProfileController
final class ProfileController: UIViewController {
private var collectionView: UICollectionView?
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
layout.sectionInset = UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 1)
let size = (view.width - 4)/3
layout.itemSize = CGSize(width: size, height: size)
collectionView = UICollectionView(frame: .zero,
collectionViewLayout: layout)
// Headers
collectionView?.register(ProfileInfoHeader.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: ProfileInfoHeader.identifier)
collectionView?.register(MyTasksCollectionCell.self,
forCellWithReuseIdentifier: MyTasksCollectionCell.identifier)
collectionView?.delegate = self
collectionView?.dataSource = self
guard let collectionView = collectionView else {
return
}
view.addSubview(collectionView)
}
extension ProfileController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyTasksCollectionCell.identifier,
for: indexPath)as! MyTasksCollectionCell
return cell
}
MyTaskCollectionCell
class MyTasksCollectionCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let task = {() -> Add in
switch (displayedTask) {
case .current:
// First segment tapped
return self.tasks[indexPath.row]
case past:
// Second segment tapped
return self.pastTasks[indexPath.row]
}
}()
let vc = MyTasksDetailController() //ERROR HERE: Missing argument for parameter 'coder' in call : Insert 'coder: <#NSCoder#>'
self.present(vc, animated: true, completion: nil)
}
MyTaskTableCell
class MyPostsTableCell: UITableViewCell {
var setdescriptionTitleLabel: String? {
didSet {
descriptionTitleLabel.text = setdescriptionTitleLabel ?? ""
}
}
var setdateLabel: String? {
didSet {
dateLabel.text = setdateLabel ?? ""
}
}
var sethourLabel: String? {
didSet {
hourLabel.text = sethourLabel ?? ""
}
}
var setDateIcon: UIImage? {
didSet {
dateIcon.image = UIImage()
}
}
var setHourIcon: UIImage? {
didSet {
hourIcon.image = UIImage()
}
}
MyTasksDetailController
class MyTasksDetailController: UIViewController {
internal var task: Add? {
didSet {
if let task = task {
setDescriptionLabel = task.description
setDescriptionTitleLabel = task.descriptionTitle
}
}
}
var setDescriptionLabel: String? {
didSet {
descriptionLabel.text = setDescriptionLabel ?? ""
}
}
var setdescriptionTitleLabel: String? {
didSet {
descriptionTitleLabel.text = setdescriptionTitleLabel ?? ""
}
}
let descriptionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 28, weight: .bold)
label.textAlignment = .center
return label
}()
let descriptionTitleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 18, weight: .bold)
label.textAlignment = .center
label.numberOfLines = 3
return label
}()
let container: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.clipsToBounds = true
v.backgroundColor = .white
v.layer.cornerRadius = 24
v.backgroundColor =
// 1
UIColor { traitCollection in
// 2
switch traitCollection.userInterfaceStyle {
case .dark:
// 3
v.layer.borderColor = UIColor.label.cgColor
return UIColor.systemBackground
default:
// 4
v.layer.borderColor = UIColor.black.cgColor
return UIColor.systemBackground
}
}
return v
}()
lazy var stackContainer: UIStackView = {
let stackContainer = UIStackView(arrangedSubviews: [stackDesLabel, stackDesTitLabel])
stackContainer.translatesAutoresizingMaskIntoConstraints = false
stackContainer.axis = .vertical
stackContainer.distribution = UIStackView.Distribution.fillEqually
return stackContainer
}()
lazy var stackDesLabel: UIStackView = {
let stackDesLabel = UIStackView(arrangedSubviews: [descriptionLabel])
stackDesLabel.translatesAutoresizingMaskIntoConstraints = false
stackDesLabel.axis = .vertical
stackDesLabel.distribution = UIStackView.Distribution.fillProportionally
return stackDesLabel
}()
lazy var stackDesTitLabel: UIStackView = {
let stackDesTitLabel = UIStackView(arrangedSubviews: [descriptionTitleLabel])
stackDesTitLabel.translatesAutoresizingMaskIntoConstraints = false
stackDesTitLabel.axis = .horizontal
stackDesTitLabel.distribution = UIStackView.Distribution.fillEqually
return stackDesTitLabel
}()
override func viewDidLoad() {
view.addSubview(stackDesLabel)
view.addSubview(stackDesTitLabel)
stackContainer.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
stackContainer.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
stackContainer.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
stackContainer.centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
stackContainer.heightAnchor.constraint(equalTo: container.heightAnchor).isActive = true
stackContainer.widthAnchor.constraint(equalTo: container.widthAnchor).isActive = true
stackDesTitLabel.topAnchor.constraint(equalTo: stackContainer.topAnchor, constant: 50).isActive = true
stackDesTitLabel.widthAnchor.constraint(equalTo: stackContainer.widthAnchor).isActive = true
stackDesTitLabel.centerXAnchor.constraint(equalTo: stackContainer.centerXAnchor).isActive = true
stackDesLabel.topAnchor.constraint(equalTo: stackDesTitLabel.bottomAnchor, constant: 50).isActive = true
stackDesLabel.leadingAnchor.constraint(equalTo: stackContainer.leadingAnchor, constant: 5).isActive = true
stackDesLabel.widthAnchor.constraint(equalTo: stackContainer.widthAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
添加(数据结构)
struct Add {
static var details: Add = Add()
var descriptionTitle: String = ""
var description: String = ""
var id: String?
var date: String = ""
var hour: String = ""
func getDict() -> [String: Any] {
let dict = [
"descriptionTitle": self.descriptionTitle,
"description": self.description,
"date": self.date,
"hour": self.hour,
] as [String : Any]
return dict
}
}
正如我所怀疑的那样,问题出在 MyTasksDetailController
与您实施
required init?(coder aDecoder: NSCoder)
如果您只是想要一个快速的解决方案,您可以根据对您的应用程序最有意义的事情做以下两件事之一:
- 删除
required init?(coder aDecoder: NSCoder)
- 像这样添加你自己的初始化器:
init() { // Keep nil if you are not initializing from XIB super.init(nibName: nil, bundle: nil) }
说明
我相信您试图实现的目标违反了初始化继承规则,这就是您收到该错误的原因。
我正在查看全部rules from here。
当您这样做时:class MyTasksDetailController: UIViewController
- 如果您遵循以下规则,您将自动从 UIViewController 继承初始化程序:
自动初始化程序继承
Rule 1
If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.
Rule 2
If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.
These rules apply even if your subclass adds further convenience initializers.
现在当您添加:
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
它违反了规则 1,您正在添加自己的指定初始化程序,因此您丢失了之前继承的所有其他初始化程序,因此您会收到此错误:
所以现在您有 2 个选项,如前所述。
1.删除 required init?(coder aDecoder: NSCoder)
如果您在情节提要中创建视图控制器,则需要此版本的 init,因为在这种情况下会自动调用它。如果您不打算这样做,您可以将其删除。如果你打算在故事板中使用它,你需要完成它:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
2。添加您自己的指定初始化器
通过添加 required init?(coder aDecoder: NSCoder)
,您丢失了之前继承的默认初始化程序,因此现在您需要创建自己的初始化程序:
init() {
// Initialize your local vars
// Call designated initializer from the super class
// Keep nil if you are not initializing from XIB
super.init(nibName: nil, bundle: nil)
}
以下任一方法都可以解决您的问题:
更新最后的想法
- 以上应该可以解决您的初始化错误
- 但是,你会在下一行出错
self.present(vc, animated: true, completion: nil)
简而言之,present
(documentation reference)只能被视图控制器调用
在您的代码中 MyTasksCollectionCell
是一个 UICollectionViewCell,因此您需要通知视图控制器您的集合视图位于其中,一个单元格被点击并且视图控制器需要处理呈现新视图。
您可以通过两种方式做到这一点:
- Delegates - 让您的视图控制器负责处理单元格点击并呈现另一个视图控制器
- Observers - 通知您的视图控制器处理单元格点击并呈现另一个视图控制器
这两个都会
这些只是给您一个想法的快速链接,但我建议您多用谷歌搜索一下,看看哪个最适合您的情况