error when declaring a new object in a UIViewController in swift - ios

I have created file called MyHelper.swift
and I created class inside it:
public class MyHelper{
//..... variables here
public init(list listOfViews: [UIView]){
self.listOfViews = listOfViews
self.time = 1.0;
}
}
then i declared an object in UIViewController like this
class ViewController: UIViewController {
var myHelper: MyHelper;
override func viewDidAppear(animated: Bool) {
myHelper = MyHelper(listOfViewsToAnimatin: listOfViews)
}
// ..... rest of the code
}
but i got error that says:
**
Class "ViewController" has no initializers.
**
I tried the default fixes suggested in xcode:
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
It caused another error.
then i tried this code from internet:
required init(coder aDecoder: NSCoder!)
{
super.init(coder: aDecoder)
}
It says :
Property self.myHelper not initialized at super.init call
How on earth i can use object of MyHelper class inside UIViewController !?

This is Swift's compile time checking at work.
You'll need to either setup the MyHelper in the init method, or mark it as optional (note the question mark at the end of the var declaration):
class ViewController: UIViewController {
var myHelper: MyHelper?
required init(coder aDecoder: NSCoder!)
{
super.init(coder: aDecoder)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
myHelper = MyHelper(listOfViewsToAnimatin: listOfViews)
}
// ..... rest of the code
}

You are initializing the MyHelper in viewDidAppear. It needs to be initialized in init (before super.init()) or you need to declare it as optional and set to nil.
var myHelper: MyHelper? = nil

You can make myHelper optional:
var myHelper:MyHelper?
When you use it, unwrap it first with:
if let myHelper = myHelper {
myHelper.yourFunction()
} else {
// self.myHelper == nil
}
Alternatively you can unwrap with !:
myHelper!.yourFunction()
But it will crash if myHelper is nil.

Related

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)
}

Swift 2.0 Subclassing a subclass of UIViewController and called convenience initializers

Have a bit of confusion regarding designated and convenience initializers for UIViewController in Swift 2.0/Xcode 7beta3. Our UIViewControllers are all defined in code, there are no Nibs
Currently class A inherits from UIViewController like this
class A : UIViewController {
convenience init() {
...
self.init(nibName:nil, bundle:nil)
...
}
}
Then class B inherits from class A and should override the convenience init and call its as super.init()
class B : A {
convenience init() {
super.init()
...
}
}
The compiler does not allow this with Must call a designated initializer of the superclass '...' error on super.init()
You need to make your initializers designated, not convenience:
class A : UIViewController {
init() {
super.init(nibName:nil, bundle:nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("")
}
}
class B : A {
override init() {
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("")
}
}
That gives you the inheritance structure you're looking for.
Take a look at these images found in the documentation.
(source: apple.com)
(source: apple.com)
According to the image convenience initializers are not inherited. So if you want to inherit you must make it a designated initializer.
class A : UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class B : A {
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
At this Point you may wonder what the heck is the difference between a designated and convenience initializer? Well, Convenience is used to call a designated initializer in the same class and you are suppose to use this to do some set up.
According to the document
Rule 2 A convenience initializer must call another initializer from the same class.
From https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html(Initializer Delegation for Class Types)
You should call it's own initializer instead:
class B : A {
convenience init() {
init()
...
}
}
And init() is automatically inherit from it's superclass version
Here are rules how communicating designated initializers and convenience initializers
rule 1:
A designated initializer must call a designated initializer from its immediate superclass.
Rule 2:
A convenience initializer must call another initializer from the same class.
Rule 3:
A convenience initializer must ultimately call a designated initializer.
A simple way to remember this is:
Designated initializers must always delegate up.
Convenience initializers must always delegate across.

Trouble creating an instance of ViewController

All,
I have a bar button item on my ViewController. I have set a computed property to will turn the BarButton off. I want to be able to set this from another class.
Here is my code in the view controller :
class ViewController: UIViewController {
var PayButton : Int {
didSet {
navigationItem.leftBarButtonItem = nil
}
}
required init(coder aDecoder: NSCoder)
{
self.PayButton = 0
super.init(coder: aDecoder)
}
When it try and create an instance on the view controller (so I can set the PayButton integer)
let test = ViewController()
I get an error saying
Missing Argument for parameter 'coder' in call
Any ideas ?
It is asking for the parameter 'coder', because you have it in the required init.
To use your code as it stands, you would need to initialise with:
let test = ViewController(coder: NSCoder)
There are several ways to get around this. The easiest would be to remove the required initialiser.
import UIKit
class ViewController: UIViewController {
var PayButton : Int = 0 {
didSet {
navigationItem.leftBarButtonItem = nil
}
}
}
and then implement with
let test = ViewController()
test.PayButton = 0
Because you have implemented the required initializer in ViewController class.
There are two solutions
Add a default initializer
init() {
super.init(nibName: nil, bundle:nil)
}
Remove the required initializer.
class ViewController: UIViewController {
var PayButton : Int {
didSet {
navigationItem.leftBarButtonItem = nil
}
}
init() {
self.PayButton = 0
super.init(nibName: nil, bundle:nil)
}
required init(coder aDecoder: NSCoder)
{
self.PayButton = 0
super.init(coder: aDecoder)
}
Try this:
This is the required initializer:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
This is the super initializer:
override init(frame: CGRect) {
super.init(frame: frame)
}
This is your convenience initializer where you can pass the size the view you want to create
convenience init(view: UIView){
self.init(frame: view.frame)
}
This is your convenience initializer where the view is initialized with a value pre defined:
convenience init(){
self.init(frame: CGRectZero) //Put you predefined value here
}

Swift 1.2: override init gives error [duplicate]

So I've just upgraded to Xcode 6.3 Beta 3 and a lot of error(s) are appearing relating to the following:
Initializer does not override a designated initializer from its superclass.
override init() {
super.init()
}
For example this is a UIButton class:
class CustomButton: UIButton {
var target: AnyObject!
var selector: Selector!
var action: (() -> Void)!
override init() { // Initializer does not override a designated initializer from its superclass
super.init() // Must call a designated initializer of the superclass 'UIButton'
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
This is one of my UIViewController classes:
class CustomAlertView: UIViewController {
required init(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
required override init() { // Initializer does not override a designated initializer from its superclass
super.init() // Must call a designated initializer of the superclass 'UIViewController'
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
My solution is a quick fix, but I think is easier than what Apple purposes on the the Release Notes. For more information search for 19775924 http://adcdownload.apple.com//Developer_Tools/Xcode_6.3_beta_3/Xcode_6.3_beta_3_Release_Notes.pdf here. What Apple says is that you create an Objective-C file and extend it (having to add it to the header files and all) and it's on "Known Issues in Xcode 6.3 beta 3", so I think is easy to do what I did:
This is how I fixed it for UIButton:
class CustomButton : UIButton {
init() {
super.init(frame: CGRectZero)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And this is one of my ViewControllers (remove public if not needed):
public class GenericViewController: UIViewController {
public init() {
super.init(nibName: nil, bundle: nil)
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I don't use IB so I also have UIView, because I do separate the view from the viewController (remove public if not needed):
public class GenericMenuView: UIView {
public init() {
super.init(frame: CGRectZero)
}
public required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I need this specially in views because I have a setupViews method that I override in all subclasses that is called on the init. And using AutoLayout I don't need any frames (so I don't override the init with the frame parameter).
So it seems you have to drop override. Oh! and be sure to not call self.init() or the class is never initialized (and it crashes after some internal timeout).
As per Apple documentation here, what you are overriding is a convenience initializer. So for your initializer to work, you will have to change the method to
override convenience init() {
super.init()
}
You can either do that, or remove the initializer if you are not really using it except for calling the superclass initializer.
I recently figured this out and I'd like to explain what the problem was. Originally answered on the Apple Developer forums.
It seems Swift has changed the strategy for initializer dependency checking or for imporing initializers.
Now if your initializers' are as shown, one way to deal with both Xcode 6.3 Beta 2 and Beta 3 is to remove all initializer definitions:
class CustomButton: UIButton {
var target: AnyObject!
var selector: Selector!
var action: (() -> Void)!
}
class CustomAlertView: UIViewController {
}
Without defining any designated initializers, classes inherit all initializers of their superclasses.
A pretty easy fix, but a big gotcha that had me stumped for a while.
I think this is way easier than it seems.
For an SKSpriteNode, I was doing this:
override init() {
let texture = SKTexture(imageNamed: "bgTile")
super.init(texture: texture, color: nil, size: texture.size())
}
The problem is init() is not the designated initializer for SKSpriteNode. So I just changed it to:
override init(texture: SKTexture!, color: UIColor!, size: CGSize) {
let texture = SKTexture(imageNamed: "bgTile")
super.init(texture: texture, color: nil, size: texture.size())
}
Now it works fine.
Solution for Error : Override init(coder aDecoder: NSCoder!) not working like expected - Swift
This works for me , Try this, Note: u must awake nib
override func awakeFromNib() {
super.awakeFromNib()
// Initialisation code
}

Initializer does not override a designated initializer from its superclass

So I've just upgraded to Xcode 6.3 Beta 3 and a lot of error(s) are appearing relating to the following:
Initializer does not override a designated initializer from its superclass.
override init() {
super.init()
}
For example this is a UIButton class:
class CustomButton: UIButton {
var target: AnyObject!
var selector: Selector!
var action: (() -> Void)!
override init() { // Initializer does not override a designated initializer from its superclass
super.init() // Must call a designated initializer of the superclass 'UIButton'
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
This is one of my UIViewController classes:
class CustomAlertView: UIViewController {
required init(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
required override init() { // Initializer does not override a designated initializer from its superclass
super.init() // Must call a designated initializer of the superclass 'UIViewController'
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
My solution is a quick fix, but I think is easier than what Apple purposes on the the Release Notes. For more information search for 19775924 http://adcdownload.apple.com//Developer_Tools/Xcode_6.3_beta_3/Xcode_6.3_beta_3_Release_Notes.pdf here. What Apple says is that you create an Objective-C file and extend it (having to add it to the header files and all) and it's on "Known Issues in Xcode 6.3 beta 3", so I think is easy to do what I did:
This is how I fixed it for UIButton:
class CustomButton : UIButton {
init() {
super.init(frame: CGRectZero)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And this is one of my ViewControllers (remove public if not needed):
public class GenericViewController: UIViewController {
public init() {
super.init(nibName: nil, bundle: nil)
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I don't use IB so I also have UIView, because I do separate the view from the viewController (remove public if not needed):
public class GenericMenuView: UIView {
public init() {
super.init(frame: CGRectZero)
}
public required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I need this specially in views because I have a setupViews method that I override in all subclasses that is called on the init. And using AutoLayout I don't need any frames (so I don't override the init with the frame parameter).
So it seems you have to drop override. Oh! and be sure to not call self.init() or the class is never initialized (and it crashes after some internal timeout).
As per Apple documentation here, what you are overriding is a convenience initializer. So for your initializer to work, you will have to change the method to
override convenience init() {
super.init()
}
You can either do that, or remove the initializer if you are not really using it except for calling the superclass initializer.
I recently figured this out and I'd like to explain what the problem was. Originally answered on the Apple Developer forums.
It seems Swift has changed the strategy for initializer dependency checking or for imporing initializers.
Now if your initializers' are as shown, one way to deal with both Xcode 6.3 Beta 2 and Beta 3 is to remove all initializer definitions:
class CustomButton: UIButton {
var target: AnyObject!
var selector: Selector!
var action: (() -> Void)!
}
class CustomAlertView: UIViewController {
}
Without defining any designated initializers, classes inherit all initializers of their superclasses.
A pretty easy fix, but a big gotcha that had me stumped for a while.
I think this is way easier than it seems.
For an SKSpriteNode, I was doing this:
override init() {
let texture = SKTexture(imageNamed: "bgTile")
super.init(texture: texture, color: nil, size: texture.size())
}
The problem is init() is not the designated initializer for SKSpriteNode. So I just changed it to:
override init(texture: SKTexture!, color: UIColor!, size: CGSize) {
let texture = SKTexture(imageNamed: "bgTile")
super.init(texture: texture, color: nil, size: texture.size())
}
Now it works fine.
Solution for Error : Override init(coder aDecoder: NSCoder!) not working like expected - Swift
This works for me , Try this, Note: u must awake nib
override func awakeFromNib() {
super.awakeFromNib()
// Initialisation code
}

Resources