Why do I have to override my init in Swift now? - swift

import Foundation
class Student: NSObject
{
var name: String
var year: Int
var major: String
var gpa : String
init(name:String, year:Int, major:String, gpa:String)
{
self.name = name
self.year = year
self.major = major
self.gpa = gpa
}
convenience init()
{
//calls longer init method written above
}
}
--
The error shows itself atthe line of the convenience init
Overriding declaration requires an 'override' keyword
I've tried Googling this and reading guides on initializers in Swift, but it seems like they were able to make their initializers just fine without overriding anything.

init is a designated initializer for NSObject. If you override it, you must mark this as override and call a superclass designated initializer. This follows the normal rules for initializer inheritance.

it looks like your convenience initializer is empty which is why you get the error. For example if you change it to:
convenience init() {
self.init(name: "", year: 0, major: "nothing", gpa: "4.0")
}
the error would go away.
I wonder why you set up Student to inherit from NSObject. It doesn't look necessary for your class.

Related

How to init a struct in swift 4.2

What I want:
To initialise a struct before use. But I really don't know how, even after a lot of trying and searching.
Example of the struct:
struct Person: Decodable {
let name: String
let age: Int
}
I want to use this struct global in my script. The way I think it would have been is like this (but it does not work, because of line 3):
import UIKit
class ViewController: UIViewController {
let personExample: Person()
func configure(person: Person) {
self.personExample = person
}
override func viewDidLoad() {
super.viewDidLoad()
print(self.personExample)
}
}
The syntax here is simply incorrect:
let personExample: Person()
What you meant was this:
let personExample: Person
Person() is the result of calling init(), which is a value, not a type, and isn't a valid initializer for this type anyway. Person is the type, which is what you want for a declaration.
However, what you've written here doesn't quite line up with the description. If you want a "global," this is actually an instance variable. What you may have meant here is the following:
var personExample = Person(name: "Bob", age: 21)
That would assign personExample to that value (and through type inference, assign the type to Person). I've used var here because configure(person:) tries to modify it.
You also may be confused about initialization of instance variables in view controllers when using storyboards. If that's your issue (for example, you're seeing errors about personExample not being set during initialization), you'll need to explain a little more about your situation and we can help you with that.
You need
var personExample: Person?
func configure(person: Person) {
self.personExample = person
}
first this let personExample: Person() is an incorrect syntax and if you changed to
var personExample: Person
it'll raise an error as it must be initated in the vc init methods , also if you don't implement coding , remove : Decodable {

Initializing Realm Object class with multiple required initilizers

I am initializing Realm object and I am getting these errors when I try to initialize the class:
After I add the initializer for realm, the errors are still there. Is this a bug with xcode?
Looking at the sample code for swift-realm ios project here, it looks like I don't need to call the required realm. Maybe the sample code is outdated.
EDIT ---
Here's a paste of the code:
class AgencyR: Object {
#objc dynamic var agency_id: String = ""
#objc dynamic var agency_name: String = ""
#objc dynamic var agency_timezone: String = ""
#objc dynamic var agency_url: String = ""
#objc dynamic var agency_lang: String = ""
#objc dynamic var agency_phone: String = ""
#objc dynamic var agency_fare_url: String = ""
required init(realm:Realm, agency_id: String, agency_name: String, agency_timezone: String, agency_url: String, agency_lang: String, agency_phone: String, agency_fare_url: String) {
self.init()
self.agency_id = agency_id
self.agency_name = agency_name
self.agency_timezone = agency_timezone
self.agency_url = agency_url
self.agency_lang = agency_lang
self.agency_phone = agency_phone
self.agency_fare_url = agency_fare_url
}
override static func primaryKey() -> String? {
return self.agency_id
}
}
If you wanted to create a designated initializer for an Object subclass, you'd need to implement all required initializers of Object since the compiler will not be able to synthetise those for you anymore.
You can get around this issue by making your custom initializer a convenience initializer rather than a designated one, which will allow you to call a designated initializer of the class rather than having to call the superclass initializer. You can still mark the convenience initializer as required.
You also have an issue in your primaryKey function. Since the function is a type function, you don't have access to the instance from inside the function, so you cannot call self to access an instance property. However, there's no need to do that anyways, since you simply need to return the variable name as a String that you want to use as a primary key.
class A: Object {
#objc dynamic var a = 1
required convenience init(_ a:Int) {
self.init()
self.a = a
}
override static func primaryKey()->String?{
return "a"
}
}
It should be -> Object, instead of ->String? as agency_id is of type Object.Try this.

Providing a default value from a class function for a constant stored property in Swift initializers?

I would like to do something similar to the following with an NSObject subclass
class Thing: NSObject {
class func defaultText() -> String { ... }
let text: String
init(text: String?) {
self.text = text ?? self.dynamicType.defaultText() // Of course, this line won't compile
super.init()
}
}
so that Thing subclasses may override defaultText() without requiring them to override the initializer. This is easy to do with a mutable stored property, but it would be nice to have it constant. Is there a way to do this?
This is a separate issue than overriding static vars in subclasses swift 1.2 . There is no desire to override a constant or a static method. The only thing in question is, in the initializer where the constant is set, is there a way to compute a value based on the specific class that is being initialized?

Why use required Initializers in Swift classes?

I am trying to understand the use of the required keyword in Swift classes.
class SomeClass
{
required init() {
// initializer implementation goes here
}
}
required doesn't force me to implement the method in my child-class. If I want to override the required designated initializer of my parent class I need to write required and not override. I know how it works but can not understand why I should do this.
What is the benefit of required?
As far as I can tell, languages like C# don't have something like this and work just fine with override.
It's actually just a way of satisfying the compiler to assure it that if this class were to have any subclasses, they would inherit or implement this same initializer. There is doubt on this point, because of the rule that if a subclass has a designated initializer of its own, no initializers from the superclass are inherited. Thus it is possible for a superclass to have an initializer and the subclass not to have it. required overcomes that possibility.
One situation where the compiler needs to be satisfied in this way involves protocols, and works like this:
protocol Flier {
init()
}
class Bird: Flier {
init() {} // compile error
}
The problem is that if Bird had a subclass, that subclass would have to implement or inherit init, and you have not guaranteed that. Marking Bird's init as required does guarantee it.
Alternatively, you could mark Bird as final, thus guaranteeing the converse, namely that it will never have a subclass.
Another situation is where you have a factory method that can make a class or its subclass by calling the same initializer:
class Dog {
var name: String
init(name: String) {
self.name = name
}
}
class NoisyDog: Dog {
}
func dogMakerAndNamer(whattype: Dog.Type) -> Dog {
let d = whattype.init(name: "Fido") // compile error
return d
}
dogMakerAndNamer is calling the init(name:) initializer on Dog or a Dog subclass. But how can the compiler be sure that a subclass will have an init(name:) initializer? The required designation calms the compiler's fears.
According to the documentation:
Write the required modifier before the definition of a class initializer to
indicate that every subclass of the class must implement that initializer
So yes, required does force all child classes to implement this constructor. However, this is not needed
if you can satisfy the requirement with an inherited initializer.
So if you have created more complex classes that cannot be fully initialized with a parent constructor, you must implement the require constructor.
Example from documentation (with some added stuff):
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
let thisNeedsToBeInitialized: String
required init() {
// subclass implementation of the required initializer goes here
self.thisNeedsToBeInitialized = "default value"
}
}
I want to draw an attention on another solution provided by Required, apart from Matt has given above.
class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
}
let instanceSubClass = subClass()
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Subclass Untitled"
As you can check in above example, I've declared required init() on superClass, init() initializer of superClass has inherited by default on subClass, So you able to create an instance of subClass let instanceSubClass = subClass().
But, suppose you want to to add one designated initializer on subClass to assign run time value to stored property neakName. Of course you can add it, but that will result to no initializers from the superClass will be inherited to subClass, So if you will create an instance of subClass you will create through its own designated initializer as below.
class superClass{
var name: String
init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
}
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
Here above, you won't be able to create an instance of subClass by just subClass(), But if you want that every subclasses of superClass must have their own init() initializer to create direct instance by subClass(). Just place required keyword before init() on superClass, it will force you to add init() initializer on subClass too - as below.
class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
} // Compiler error <------------ required `init()` must be provided by subClass.
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
SO, use required keyword before initializer on superclass, when you want all subclasses must have been implemented required initializer of superclass.
If you are trying to add you own initialiser in the sub class, then you have to follow certain things those were declared in super class. So it make sure that you will not forget to implement that required method. If you forget compiler will give you error // fatal error, we've not included the required init()
. Another reason is it creates a set of conditions that ever sub class should follow it the sub class is defining its own initialiser.

Init with default vs convenience initialiser

Is there any difference between init with default value vs calling convenience initialiser ? I try to figure out when should I use convenience instead of init with default.
class Food
{
var name :String
init(name : String = "Unknow")
{
self.name = name
}
}
And this :
class Food
{
var name :String
init(name : String)
{
self.name = name
}
convenience init()
{
self.init(name : "Unkow")
}
}
Convenience initializer is easier for users of the class than a designated initializer with a default value because Xcode lists the two initializers by autocompletion.
Autocompletion for a designated initializer with a default value:
Autocompletion for a designated initializer and convenience initializer:
The screenshots are taken with Xcode 6.2. Unless Xcode supports autocompletion for default values, the convenience initializer is easier for the users, especially if you design a framework for people.
A disadvantage of a convenience initializer is, as Kelvin mentioned in his comment, you cannot use the convenience initializer from the subclass initializer.