Missing argument for parameter 'coder' in call in Swift - ios

class SecondViewController:UIViewController {
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
//Custom logic here
}
}
Quite a newbie question:
a view controller(SecondViewController), inherent from UIViewController needs a designated init function like above.
In this case, how should I call it, given I am not sure what the value for "coder" should be? I used to call the controller as: SecondViewController(), but it gives:
Missing argument for parameter 'coder' in call
I understand coder parameter has to be provided, but want to ask what its value comes from.

Thanks for the answers from #Chackle. Finally the solution I figured out is below.
What I want:
Inherit my SecondViewController from UIViewController
Simply to initialize any new SecondViewController as SecondViewController()
Solution:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
init() {
super.init(nibName: nil, bundle: nil)
//Do whatever you want here
}
"required init(coder aDecoder: NSCoder)" is a must if you create a subclass of UIViewController. And so is "super.init(nibName: nil, bundle: nil)", because it is the way how UIViewController does initialization.

Related

not initialized at super.init call

New to iOS.
How should I resolve this:
#objc protocol NwNamew {
init(vm: ViewModel)
}
class ViewController: UIViewController, NwNamew {
var viewModel: ViewModel
required init(vm: ViewModel) {
self.viewModel = vm
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
getting error: Property 'self.viewModel' not initialized at super.init call
Before you call super.init(coder:) you have to have initialised all the variables in the class. As you aren't implementing the init(coder:) function in your class you can remove this super.init(coder:) call. This will get rid of your compile error.
You could also resolve this error by making the parameter as Optional, as so
var viewModel: ViewModel?
Optionals are parameters that can be nil and need to be unwrapped before usage.
You could read more here about Optionals:
Optionals

Assigning viewModel on Controller Init?

I am using MVVM and want to assign my viewModel to the viewController on the Controllers init. I thought I would achieve this like so:
class LoginViewController: UIViewController, UITextFieldDelegate {
init(loginViewModel: LoginViewModel) {
self.loginViewModel = loginViewModel
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
However I get the error:
Super.init isn't called on all paths before returning from initializer
Is this not the correct route to take? also how would I init the viewModel correctly when it requires an object to do so, but it has to perform a network request first? Init with a blank object instance?
Thanks
edit: this is what im trying now
initWithViewAndViewModel:(loginView: LoginView, loginViewModel: LoginViewModel) {
super.init()
self.loginView = loginView
self.loginViewModel = loginViewModel
}
As a best practice,
Step 1:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Step 2:
init(loginViewModel : LoginViewModel) {
super.init(nibName: nil, bundle: nil)
initWithModel:(loginViewModel: LoginViewModel)
}
Step 3: implement initWithModel function
Try adding this if it works:
convenience init() {
self.init(loginViewModel: nil)
}
init(loginViewModel: LoginViewModel?) {
self.loginViewModel = loginViewModel
super.init(nibName: nil, bundle: nil)
}
Please go through this link it might help: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_324

Has no accessible initializers (UITableView) [duplicate]

Apologies if this has been asked before, I've searched around a lot and many answers are from earlier Swift betas when things were different. I can't seem to find a definitive answer.
I want to subclass UIViewController and have a custom initializer to allow me to set it up in code easily. I'm having trouble doing this in Swift.
I want an init() function that I can use to pass a specific NSURL I'll then use with the view controller. In my mind it looks something like init(withImageURL: NSURL). If I add that function it then asks me to add the init(coder: NSCoder) function.
I believe this is because it's marked in the superclass with the required keyword? So I have to do it in the subclass? I add it:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Now what? Is my special initializer considered a convenience one? A designated one? Do I call a super initializer? An initializer from the same class?
How do I add my special initializer onto a UIViewController subclass?
class ViewController: UIViewController {
var imageURL: NSURL?
// this is a convenient way to create this view controller without a imageURL
convenience init() {
self.init(imageURL: nil)
}
init(imageURL: NSURL?) {
self.imageURL = imageURL
super.init(nibName: nil, bundle: nil)
}
// if this view controller is loaded from a storyboard, imageURL will be nil
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
For those who write UI in code
class Your_ViewController : UIViewController {
let your_property : String
init(your_property: String) {
self.your_property = your_property
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) is not supported")
}
}
This is very similar to the other answers, but with some explanation. The accepted answer is misleading because its property is optional and doesn't expose the fact that your init?(coder: NSCoder) MUST initialize each and every property and the only solution to that is having a fatalError(). Ultimately you could get away by making your properties optionals, but that doesn't truly answer the OP’s question.
// Think more of a OnlyNibOrProgrammatic_NOTStoryboardViewController
class ViewController: UIViewController {
let name: String
override func viewDidLoad() {
super.viewDidLoad()
}
// I don't have a nib. It's all through my code.
init(name: String) {
self.name = name
super.init(nibName: nil, bundle: nil)
}
// I have a nib. I'd like to use my nib and also initialze the `name` property
init(name: String, nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle? ) {
self.name = name
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
// when you do storyboard.instantiateViewController(withIdentifier: "ViewController")
// The SYSTEM will never call this!
// it wants to call the required initializer!
init?(name: String, coder aDecoder: NSCoder) {
self.name = "name"
super.init(coder: aDecoder)
}
// when you do storyboard.instantiateViewController(withIdentifier: "ViewController")
// The SYSTEM WILL call this!
// because this is its required initializer!
// but what are you going to do for your `name` property?!
// are you just going to do `self.name = "default Name" just to make it compile?!
// Since you can't do anything then it's just best to leave it as `fatalError()`
required init?(coder aDecoder: NSCoder) {
fatalError("I WILL NEVER instantiate through storyboard! It's impossible to initialize super.init?(coder aDecoder: NSCoder) with any other parameter")
}
}
You basically have to ABANDON loading it from storyboard. Why?
Because when you call a viewController storyboard.instantiateViewController(withIdentifier: "viewController") then UIKit will do its thing and call
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
You can never redirect that call to another init method.
Docs on instantiateViewController(withIdentifier:):
Use this method to create a view controller object to present
programmatically. Each time you call this method, it creates a new
instance of the view controller using the init(coder:) method.
Yet for programmatically created viewController or nib created viewControllers you can redirect that call as shown above.
Convenience initializers are secondary, supporting initializers for a
class. You can define a convenience initializer to call a designated
initializer from the same class as the convenience initializer with
some of the designated initializer’s parameters set to default values.
You can also define a convenience initializer to create an instance of
that class for a specific use case or input value type.
They are documented here.
If you need a custom init for a popover for example you can use the following approach:
Create a custom init that uses the super init with nibName and bundle and after that access the view property to force the load of the view hierarchy.
Then in the viewDidLoad function you can configure the views with the parameters passed in the initialization.
import UIKit
struct Player {
let name: String
let age: Int
}
class VC: UIViewController {
#IBOutlet weak var playerName: UILabel!
let player: Player
init(player: Player) {
self.player = player
super.init(nibName: "VC", bundle: Bundle.main)
if let view = view, view.isHidden {}
}
override func viewDidLoad() {
super.viewDidLoad()
configure()
}
func configure() {
playerName.text = player.name + "\(player.age)"
}
}
func showPlayerVC() {
let foo = Player(name: "bar", age: 666)
let vc = VC(player: foo)
present(vc, animated: true, completion: nil)
}

Error while initialisation of TableViewCell with Buttons [duplicate]

I decided to continue my remaining project with Swift. When I add the custom class (subclass of UIViewcontroller) to my storyboard view controller and load the project, the app crashes suddenly with the following error:
fatal error: use of unimplemented initializer 'init(coder:)' for class
This is a code:
import UIKit
class TestViewController: UIViewController {
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Custom initialization
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// #pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
}
Please suggest something
Issue
This is caused by the absence of the initializer init?(coder aDecoder: NSCoder) on the target UIViewController. That method is required because instantiating a UIViewController from a UIStoryboard calls it.
To see how we initialize a UIViewController from a UIStoryboard, please take a look here
Why is this not a problem with Objective-C?
Because Objective-C automatically inherits all the required UIViewController initializers.
Why doesn't Swift automatically inherit the initializers?
Swift by default does not inherit the initializers due to safety. But it will inherit all the initializers from the superclass if all the properties have a value (or optional) and the subclass has not defined any designated initializers.
Solution
1. First method
Manually implementing init?(coder aDecoder: NSCoder) on the target UIViewController
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
2. Second method
Removing init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) on your target UIViewController will inherit all of the required initializers from the superclass as Dave Wood pointed on his answer below
Another option besides #3r1d's is to instead remove the following init method from your class:
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Custom initialization
}
Including that init method, prevents the sub class from inheriting the init(coder aDecoder: NSCoder!) from its super class. By not including it, your class will inherit both.
Note: See WWDC 2014 Session 403 "Intermediate Swift" at about the 33:50 mark for more details.
For people having the same issue with swift UICollectionViewCells, add the code that #3r1d suggested to your custom UICollectionViewCell class and not to the View Controller:
init(coder aDecoder: NSCoder!)
{
super.init(coder: aDecoder)
}
For those needing the code in Swift:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
[Edit] This was for an older version of Swift. Possibly doesn't work anymore.
I had this problem in a programmatic collectionView cell and even though the op is asking about a vc I still landed on this question when searching for an answer. For me the issue was I did have
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
implemented so the top answer didn't work. What I didn't have in the cell was the initializer:
// my programmatic cell was missing this
override init(frame: CGRect) {
super.init(frame: frame)
}
Once I added it the error went away
Rather than adding some methods for making internal mechanism work fine, i would go with defining my attributes as #lazy and initialise them right in the class scope.

Fatal error: use of unimplemented initializer 'init(coder:)' for class

I decided to continue my remaining project with Swift. When I add the custom class (subclass of UIViewcontroller) to my storyboard view controller and load the project, the app crashes suddenly with the following error:
fatal error: use of unimplemented initializer 'init(coder:)' for class
This is a code:
import UIKit
class TestViewController: UIViewController {
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Custom initialization
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// #pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
}
Please suggest something
Issue
This is caused by the absence of the initializer init?(coder aDecoder: NSCoder) on the target UIViewController. That method is required because instantiating a UIViewController from a UIStoryboard calls it.
To see how we initialize a UIViewController from a UIStoryboard, please take a look here
Why is this not a problem with Objective-C?
Because Objective-C automatically inherits all the required UIViewController initializers.
Why doesn't Swift automatically inherit the initializers?
Swift by default does not inherit the initializers due to safety. But it will inherit all the initializers from the superclass if all the properties have a value (or optional) and the subclass has not defined any designated initializers.
Solution
1. First method
Manually implementing init?(coder aDecoder: NSCoder) on the target UIViewController
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
2. Second method
Removing init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) on your target UIViewController will inherit all of the required initializers from the superclass as Dave Wood pointed on his answer below
Another option besides #3r1d's is to instead remove the following init method from your class:
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Custom initialization
}
Including that init method, prevents the sub class from inheriting the init(coder aDecoder: NSCoder!) from its super class. By not including it, your class will inherit both.
Note: See WWDC 2014 Session 403 "Intermediate Swift" at about the 33:50 mark for more details.
For people having the same issue with swift UICollectionViewCells, add the code that #3r1d suggested to your custom UICollectionViewCell class and not to the View Controller:
init(coder aDecoder: NSCoder!)
{
super.init(coder: aDecoder)
}
For those needing the code in Swift:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
[Edit] This was for an older version of Swift. Possibly doesn't work anymore.
I had this problem in a programmatic collectionView cell and even though the op is asking about a vc I still landed on this question when searching for an answer. For me the issue was I did have
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
implemented so the top answer didn't work. What I didn't have in the cell was the initializer:
// my programmatic cell was missing this
override init(frame: CGRect) {
super.init(frame: frame)
}
Once I added it the error went away
Rather than adding some methods for making internal mechanism work fine, i would go with defining my attributes as #lazy and initialise them right in the class scope.

Resources