Confusion between self and super in a subclass - ios

Let's say you have a class named Vehicle:
class Vehicle {
var name: String
var size: Int
init(name: String, size: Int) {
self.name = name
self.size = size
}
convenience init(name: String) {
self.init(name: name, size: 100)
}
func operate() {
print("operate")
}
}
If I have a subclass named Car and create a convenience initializer:
class Car: Vehicle {
convenience init(size: Int) {
self.init(name: "Vehicle", size: size)
}
}
the super class' initializer is made available using self.
But, if I want to override the super class' method, it's made available by using super:
class Car: Vehicle {
// redacted
override func operate() {
super.operate()
print("operate a car")
}
}
If the subclass wants to use the inherited method, it's made available by using self:
class Car: Vehicle {
// redacted
func drive() {
self.operate()
print("drive")
}
}
I understand that class methods are instance methods, meaning self refers to the instance of the class. I'm guessing when the subclass inherits the super class' method, it becomes its own instance method. Why does it not apply to overriding? I'm getting confused between the usage of self and super.

Why does it not apply to overriding?
Well, in this code:
class Car: Vehicle {
// redacted
override func operate() {
super.operate()
print("operate a car")
}
}
self.operate would refer to the overridden method that is in Car. In other words, if you called self.operate(), it would create infinite recursion. On the other hand, super.operate refers to:
func operate() {
print("operate")
}
Think of it like this: when you override a method, you kind of "lose" the version of the method that you inherit, and you can only use super to access the original in the super class.
Also, no one stops you from doing:
class Car: Vehicle {
func drive() {
super.operate()
print("drive")
}
}
It's just that in this case, super.operate() and this.operate() do exactly the same thing, since operate is not overridden in the subclass.
On the other hand, it is illegal to call super.init in a convenience initialiser. You must delegate to a self.init in a convenience initialiser. And in this case, the super class initialisers are inherited because you don't have any designated initialisers (in general, they aren't inherited!). Read more about initialisers here.

Related

Property not initialized at super.init call using MVVM with convenience init

I have a View Model that subclasses NSObject as it is my UICollectionViewDataSource
I'd like to pass a service into this via dependancy injection.
I'm getting an error though
Property 'self.chatService' not initialised at super.init call
class ChatQuestionsViewModel: NSObject {
fileprivate var chatService: ChatService
convenience init(chatService: ChatService = ChatService()) {
self.init()
self.chatService = chatService
}
private override init() {
super.init()
}
}
And it appears to be focused on the super.init() line.
How can I initialise this class? I am unsure what I am doing wrong.
You cannot have a convenience initializer in this case. The rules of initializers state that you have to guarantee that all stored properties get initialized.
Convenience initializers are just that: for convenience only. This means it must not be necessary to use them to create an instance of the object. However if code uses your only non-convenience init, there's no initialization of chatService. (Never mind that your non-convenience init is private; that doesn't help).
Fixed result:
class ChatQuestionsViewModel: NSObject {
fileprivate var chatService: ChatService
init(chatService: ChatService = ChatService()) {
self.chatService = chatService
super.init()
}
}

Class-Only Protocols in Swift

I want some of my classes (not all) to conform using 'Class-Only Protocols' from docs. What I am doing is
protocol RefreshData: class, ClassA, ClassB
{
func updateController()
}
and I am getting the errors
non class type 'RefreshData cannot inherit from classA
non class type 'RefreshData cannot inherit from classB
I'm not sure I am following exactly as in the docs. Does anyone have any ideas about this?
Swift 4 allows you to combine types, so you can have your protocol and then create, for example, a type alias to combine it with a specific class requirement.
For (a contrived) example:
typealias PresentableVC = UIViewController & Presentable
For the presented code:
The problem is that you're trying to limit to specific classes and Swift can't do that (at the moment anyway). You can only limit to classes and inherit from other protocols. Your syntax is for protocol inheritance but you're trying to use it as a class limitation.
Note that the purpose of class protocols is:
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics.
The answers provided by Chris and Wain are correct. I'm just adding a few more details here.
Defining a protocol
You must distinguish the concept of declaring a protocol (available for classes)
protocol RefreshData: class {
func updateController()
}
Defining a class
...from the concept of conforming your class to a protocol
class ClassA: RefreshData {
func updateController() {
}
}
Conforming a class you don't own
Sometimes you want to conform a class to a protocol but you don't own the source code for that class. In this case you can use an extension
extension ClassB: RefreshData {
func updateController() {
}
}
Latest version of Swift can do it!
I would do a protocol and protocol extensions that target the classes you want! (constraint the extension to specific class)
protocol Movable {
func moveForward()
func moveBackward()
}
extension Movable where Self: Car {
func moveForward() {
self.location.x += 10;
}
func moveBackward() {
self.location.x -= 10;
}
}
extension Movable where Self: Bike {
func moveForward() {
self.x += 1;
}
func moveBackward() {
self.x -= 1;
}
}
class Car: Movable {
var location: CGPoint
init(atLocation location: CGPoint) {
self.location = location
}
}
class Bike: Movable {
var x: Int
init(atX x: Int) {
self.x = x
}
}
protocol RefreshData : class
{
func updateController()
}
class ClassA : RefreshData
{
func updateController() {}
}
class ClassB : RefreshData
{
func updateController() {}
}

Swift dispatch to overridden methods in subclass extensions

overriding method signatures in extensions seems to produce unpredictable results in certain cases. The following example demonstrates two different results with a similar pattern.
class A: UIViewController {
func doThing() {
print("dothing super class")
}
override func viewDidLoad() {
print("viewdidload superclass")
super.viewDidLoad()
}
}
class B: A { }
extension B {
override func doThing() {
print("dothing sub class")
super.doThing()
}
override func viewDidLoad() {
print("viewdidload subclass")
super.viewDidLoad()
}
}
let a: A = B()
a.doThing()
let vc: UIViewController = B()
vc.viewDidLoad()
This prints :
dothing super class
viewdidload subclass
viewdidload superclass
You can see this skips the B's implementation of doThing when it is cast as A, however includes both implementations of viewDidLoad when cast as UIViewController. Is this the expected behavior? If so, what is the reason for this?
ENV: Xcode 7.3, Playground
The surprise here is that the compiler permits the override in the extension. This doesn't compile:
class A {
func doThing() {
print("dothing super class")
}
}
class B: A {
}
extension B {
override func doThing() { // error: declarations in extensions cannot override yet
print("dothing sub class")
super.doThing()
}
}
In your example, it appears that the compiler gives you a pass because A derives from NSObject — presumably in order to allow this class to interact with Objective-C. This does compile:
class A : NSObject {
func doThing() {
print("dothing super class")
}
}
class B: A {
}
extension B {
override func doThing() {
print("dothing sub class")
super.doThing()
}
}
My guess is that the fact you're allowed to do this override at all is itself possibly a bug. The docs say:
Extensions can add new functionality to a type, but they cannot override existing functionality.
And overriding is nowhere listed as one of the things an extension can do. So it seems like this should not compile. However, perhaps this is permitted deliberately for compatibility with Objective-C, as I said before. Either way, we are then exploring an edge case, and you have very nicely elicited its edginess.
In particular, the preceding code still doesn't cause dynamic dispatch to become operational. That's why you either have to declare doThing as dynamic, as suggested by #jtbandes, or put it in the actual class rather than the extension — if you want polymorphism to operate. Thus, this works the way you expect:
class A : NSObject {
dynamic func doThing() {
print("dothing super class")
}
}
class B: A {
}
extension B {
override func doThing() {
print("dothing sub class")
super.doThing()
}
}
And so does this:
class A : NSObject {
func doThing() {
print("dothing super class")
}
}
class B: A {
override func doThing() {
print("dothing sub class")
super.doThing()
}
}
My conclusion would be: Very nice example; submit it to Apple as a possible bug; and Don't Do That. Do your overriding in the class, not in the extension.

Difference between class func vs only func

Whats the difference between these 2?
extension UIFont {
class func PrintFontFamily(font: FontName) {
let arr = UIFont.fontNamesForFamilyName(font.rawValue)
for name in arr {
println(name)
}
}
}
extension UIFont {
func PrintFontFamily(font: FontName) {
let arr = UIFont.fontNamesForFamilyName(font.rawValue)
for name in arr {
println(name)
}
}
}
A class func is a class method. It is called by sending a message to the class.
A func is an instance method. It is called by sending a message to an instance of the class.
The difference is that you call an class function like this:
UIFont.PrintFontFamily("test")
But 'constructing' the function with just the func keyword require create instance of the class and call the method on that instance:
var myFont = UIFont()
myFont.PrintFontFamily("test")
"Instance methods are methods that are called on an instance of a particular type. You can also define methods that are called on the type itself. These kinds of methods are called type methods. You indicate type methods by writing the keyword static before the method’s func keyword. Classes may also use the class keyword to allow subclasses to override the superclass’s implementation of that method."
Instance method.
class Counter {
var count = 0
func increment() {
++count
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
Usage:
let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.incrementBy(5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0
Type methods:
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
Usage:
SomeClass.someTypeMethod()
A class function is called with the class :
UIFont.PrintFontFamily("Helvetica Neue")
A non class function is a method you call from an instantiated object :
let font = UIFont(name: "Helvetica Neue", size: 30)
font.PrintFontFamily("Helvetica Neue")
In that case, you should use a class func
A class func is called on the type itself, while just func is called on the instance of that type.
An example:
class Test {
func test() {
}
}
To call test():
Test().test()
Here is the same thing with a class func
class Test {
class func test() {
}
}
To call test():
Test.test()
So, you don't have to make an instance of the class.
You can also call a static func. The difference between a static func and a class func is that static func translates into class final func which just means that subclasses cannot override the function.

Swift - How can I override an extension method in a concrete subclass

I have an extension on UIView implementing a protocol
protocol SomeProtocol {
var property : Int
}
extension UIView : SomeProtocol {
var property : Int {
get {
return 0
}
set {
// do nothing
}
}
}
in a concrete subclass I want to override this extension method:
class Subclass : UIView, SomeProtocol {
var _property : Int = 1
var property : Int {
get { return _property}
set(val) {_property = val}
}
}
I set breakpoints and see that the extension method is called and not the concrete subclass method:
var subclassObject = Subclass()
someObject.doSomethingWithConcreteSubclassObject(subclassObject)
// other code;
fun doSomethingWithConcreteSuclassObject(object : UIView) {
var value = object.property // always goes to extension class get/set
}
As others have noted, Swift does not (yet) allow you to override a method declared in a class extension. However, I'm not sure whether you'll ever get the behavior you want even if/when Swift someday allows you to override these methods.
Consider how Swift deals with protocols and protocol extensions. Given a protocol to print some metasyntactic variable names:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
An extension to provide default implementations:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
And a class that conforms to the protocol:
class FooBar : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
}
Swift will use dynamic dispatch to call the appropriate implementations of foo() and bar() based on each variable's runtime type rather than on the type inferred by the compiler:
let a = FooBar()
a.foo() // Prints "FOO"
a.bar() // Prints "BAR"
let b: Metasyntactic = FooBar()
b.foo() // Prints "FOO"
b.bar() // Prints "BAR"
If, however, we extend the protocol further to add a new method:
extension Metasyntactic {
func baz() -> String {
return "baz"
}
}
And if we override our new method in a class that conforms to the protocol:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift will now use static dispatch to call the appropriate implementation of baz() based on the type inferred by the compiler:
let a = FooBarBaz()
a.baz() // Prints "BAZ"
let b: Metasyntactic = FooBarBaz()
b.baz() // Prints "baz"
Alexandros Salazar has a fantastic blog post explaining this behavior in depth, but suffice it to say that Swift only uses dynamic dispatch for methods declared in the original protocol, not for methods declared in protocol extensions. I imagine the same would be true of class extensions, as well.
I know this question has been asked a while ago. But this will be handy for someone who looking for an easier way. There is a way of overriding an extension methods. I know its bit hacky but it does the job beautifully.
If you declare your protocol with #objc
#objc protocol MethodOverridable {
func overrideMe()
}
In Extension
extension MainClass: MethodOverridable {
func overrideMe() {
print("Something useful")
}
}
Subclass - You can able to override it in your subclass. It works like a magic. Well, not really when adding #objc it exposes your protocol to Objective-C and its Runtime. That allows your subclass to override.
class SubClass: MainClass {
override func overrideMe() {
print("Something more useful")
}
}
Swift 5
class Class
{
#objc dynamic func make() { print("make from class") }
}
class SubClass: Class {}
extension SubClass {
override func make() {
print("override")
}
}
It looks like you can override property for 2nd super class property. For example, you can access UIView property by making extension to the UILabel wanting to override frame property of UIView. This sample works for me in Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}
You can't do this through normal means.
It's in Apple's docs that you can't override a method in an extension in a subclass.
Also, extensions can add new functionality to a type, but they cannot override existing functionality.
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
I think you forgot to override the superclass property in your subclass:
class Subclass : UIView {
var _property : Int = 1
override var property : Int {
get { return _property}
set(val) {_property = val}
}
}

Resources