swift subclasses used in generics don't get called when inheriting from NSObject - swift

Partial Solution Update at the end!
Attached is code that produces odd behavior. I copied it out of a swift playground so it should run in one fine.
I created a subclass in my project and passed it to my generic class as the concrete type. However, I quickly noticed that only the base class methods are called. This is shown with myBase and mySub below. Despite the generic class being instantiated as <mySub>, only the base methods are called. The print lines for the subclass are never shown.
Well, I found a simple way around that and that is to not inherit from NSObject. When I used swift native classes, the subclass methods are in fact called. These are secondBase and secondSub.
How do I pass a subclass into a generic class and get the actual subclass to receive calls when inheriting from NSObject?
And why would behavior be different?
import Foundation
// The Protocol
protocol P {
init ()
func doWork() -> String
}
// Generic Class
class G<T: P> {
func doThing() -> String {
let thing = T()
return thing.doWork()
}
}
// NSObject Base Class with Protocol
class A1: NSObject, P {
override required init() {
super.init()
}
func doWork() -> String {
return "A1"
}
}
// NSObject Sub Class
class B1: A1 {
required init() {
super.init()
}
override func doWork() -> String {
return "B1"
}
}
// Swift Base Class
class A2: P {
required init() {
}
func doWork() -> String {
return "A2"
}
}
// Swift Sub Class
class B2: A2 {
required init() {
super.init()
}
override func doWork() -> String {
return "B2"
}
}
print ("Sub class failure with NSObject")
print ("Recieved: " + G<B1>().doThing() + " Expected: B1 - NSObject Sub Class Generic (FAILS)")
print ("\nSub class success with Swift Native")
print ("Recieved: " + G<B2>().doThing() + " Expected: B2 - Swift Sub Class Generic (SUCCEEDS)")
print("")
#if swift(>=5.0)
print("Hello, Swift 5.0")
#elseif swift(>=4.1)
print("Hello, Swift 4.1")
#elseif swift(>=4.0)
print("Hello, Swift 4.0")
#elseif swift(>=3.0)
print("Hello, Swift 3.x")
#else
print("Hello, Swift 2.2")
#endif
Output:
Sub class failure with NSObject
Recieved: A1 Expected: B1 - NSObject Sub Class Generic (FAILS)
Sub class success with Swift Native
Recieved: B2 Expected: B2 - Swift Sub Class Generic (SUCCEEDS)
Hello, Swift 5.0
Partial solution update:
Moving the protocol conformance from the base class to the sub class allows the sub class to behave correctly. Definitions become:
class A1: NSObject
class B1: A1, P
The problem is the base class can no longer be used directly at all when no functionality beyond it is needed. This is mostly an issue if the protocol being conformed to has an associated type. When this is true, you must have a concrete class that conforms to the protocol for use in generics.
One use case here is expecting a base class in the generics (with a protocol involving an associated type) which allows something to function without caring what actual sub class was passed in. This actually ends up being a poor man's form of type erasure in some cases. And you can still use the same generic with the subclass.
G<A1>()
G<B1>()
This was derived from a similar question here: Generic Class does not forward delegate calls to concrete subclass
Partial options are:
remove NSObject and use swift native classes only
when NSObject is required, try to separate protocol conformance from inheritance of NSObject
UPDATE ON THE BELOW IDEA: Doesn't Work
I am going to test if providing an additional layer changes the behavior. Basically have 3 layers, Base class inheriting from NSObject, base Protocol class adding the protocol but inheriting from base and then specific classes. If it can distinguish between the base protocol class and the specific subclass in that case, that would be a functional workaround in all use cases. (and may explain why Apple's NSManagedObject works fine)
Still seems like a bug though.

I was able to confirm your results and submitted it as a bug, https://bugs.swift.org/browse/SR-10617. Turns out this is a known issue! I was informed (by good old Hamish) that I was duplicating https://bugs.swift.org/browse/SR-10285.
In my bug submission, I created a clean compact reduction of your example, suitable for sending to Apple:
protocol P {
init()
func doThing()
}
class Wrapper<T:P> {
func go() {
T().doThing()
}
}
class A : NSObject, P {
required override init() {}
func doThing() {
print("A")
}
}
class B : A {
required override init() {}
override func doThing() {
print("B")
}
}
Wrapper<B>().go()
On Xcode 9.2, we get "B". On Xcode 10.2, we get "A". That alone is enough to warrant a bug report.
In my report I listed three ways to work around the issue, all of which confirm that this is a bug (because none of them should make any difference):
make the generic parameterized type's constraint be A instead of P
or, mark the protocol P as #objc
or, don't have A inherit from NSObject
UPDATE: And it turns out (from Apple's own release notes) there's yet another way:
mark A's init as #nonobjc

This is not an answer so much as a way to avoid the problem.
In most of my code, I did not have to conform to NSObjectProtocol only Equatable and/or Hashable. I have implemented those protocols on the objects that needed it.
I then went through my code, removed all NSObject inheritance except on those classes which inherit from an Apple protocol or object that requires it (Like UITableViewDataSource).
The classes that are required to inherit from NSObject are Generic but they are not typically handed into other Generic classes. Therefore the inheritance works fine. In my MVVM pattern these tend to be the intermediate classes that work with view controllers to make logic like table views reusable. I have a tableController class that conforms to the UITableView protocols and accepts 3 generic viewModel types allowing it to provide the table logic for 95% of my views with no modifications. And when it needs it, subclasses easily provide alternate logic.
This is a better strategy as I am no longer randomly using NSObject for no reason.

This is a second way to avoid the problem.
#matt originally suggested this but then deleted his answer. It is a good way to avoid the problem. His answer was simple. Mark the protocol with objc like this:
// The Protocol
#objc protocol P {
init ()
func doWork() -> String
}
This solves the above sample code and you now get the expected results. But doing this has side effects for swift. At least one of those is here:
How to use #objc protocol with optional and extensions at the same time?
For me, it began a chain of having to make all my protocols objc compatible. That made the change not worth it for my code base. I was also using extensions.
I decided to stay with my original answer at least until Apple fixes this bug or there is a less invasive solution.
I thought this one should be documented in case it helps someone else facing this problem.

Related

How to implement "abstract" property initializers in Swift

So far I have only worked on Objectiv-C projects and now started my first Swift project.
I know that Swift does not support abstract classes but I would like to know what is the best way to model / solve this in Swift:
// Abstract implementation
public abstract class MyClass {
private SomeBaseClass someProperty;
MyClass() {
initProperties();
}
abstract void initProperties(); // Init someProperty with some child class of SomeBaseClass.
}
// Objectiv-C
#implementation MyClass
- (id)init {
self = [super init];
if (self) {
[self initProperties];
}
return self;
}
- (void)initProperties {
// Override in inherited classes
}
// Swift
class MyClass {
// Should not be optional since MyClass should be required to have someProperty != nil
let someProperty: SomeBaseClass;
override init() {
super.init();
initProperties();
}
func initProperties() {
// Cannot be empty since someProperty is non-optional and needs to be initialized
// Cannot be empty since Swift does not support abstract methods
}
}
Of course it would be possible to define someProperty as optional SomeBaseClass? but in this case every time the property is used it has to be tested and unwrapped.
Is there a better way to solve this?
EDIT:
I know that Swift uses protocols to create an abstraction similar to abstract classes. However I do not understand how this concept can solve the concrete problem / question.
In other programming languages the abstract class MyClass can use the property someProperty in many different places while leaving the burden to initialize the property with a value with its concrete subclasses.
Although I read the article linked by #MohamendS and the answers to the possible dublicate answer I do not understand how to achieve the same using protocols.
MyClass has only one abstract function while all other functions are implemented. Thus MyClass itself cannot be a protocol since protocols cannot implement functions (can they?)
MyClass could only implement another protocol which defines that there has to be a initProperties method. But in this case MyClass would need to provide an implementation of this method which brings us back to the same problem.
I guess I can't see the wood for the trees, but how can protocols help here?
Abstraction concept in Swift is used with protocols, i suggest reading this article to know more and here is an example
protocol Abstraction {
var foo: String { get }
func fee()
init(with foo: String)
}
class A: Abstraction {
required init(with foo: String) {
self.foo = foo
}
var foo: String = ""
func fee() {
}
}
Edit: on your point, that
protocols can't implement functions
You can't but what you can do is extends those protocols using extension and give them an initial implementation therefore you don't have to implement them in the class and you can when you feel you'd like to, check the code below
class A: Abstraction {
required init(with foo: String) {
self.foo = foo
}
var foo: String = ""
//you don't have to implement func foo anymore as its extended in the extension
}
extension Abstraction {
func fee() {
print("ok")
}
}
let a = A(with: "foo")
a.fee() // this will trigger the extension implementation,
Now to use init inside the extension body so you wont have to type them in each confirmation, check out the code below
protocol Abstraction {
var foo: String { get set }
func fee()
init()
init(with foo: String)
}
class A: Abstraction {
required init() { }
var foo: String = ""
//you don't have to implement func foo anymore as its extended in the extension
// you don't have to implement the custom init anymore too
}
extension Abstraction {
init(with foo: String) {
self.init()
self.foo = foo
}
func fee() {
print("ok")
}
}
There are many possible answers to this question depending on how MyClass is used. As written, there's of course no reason for someProperty to be in the base class at all, and there's definitely no reason for an initProperties() method (that should be in init).
I realize this is "just an example," but it demonstrates a common problem of creating hierarchies that aren't needed. There are ways to write this code using a semi-abstract base class, but generally that should be avoided, so the first question is what you're using this for and can we avoid this problem entirely?
To answer the question as given, you'd probably start by making a default SomeBaseClass, so that the abstract class can just assign someProperty = SomeBaseClass().
If that's impossible, generally you'd use a ! type:
let someProperty: SomeBaseClass!
And you implement initProperties() with a fatalError:
func initProperties() { fatalError("Implement in subclass") }
Alternately, it can be convenient to implement someProperty as a computed variable, and implement it based on some other property in the subclasses
var someProperty: SomeBaseClass { fatalError() }
But this is really a last resort. Any time you find yourself having to write fatalError you're probably on the wrong track, and you don't need a trick to get around it; you need to reconsider the problem.
You should first think about how MyClass is used, and consider whether it can be a value type. Separately, you should think about whether it can be a protocol that matches the use case. Protocols are not just abstract interfaces that hide implementations. They are a view onto a conforming type to solve a specific problem. That's why there's a Collection protocol that provides access to dozens of algorithms for numerous, otherwise unrelated types, not an ArrayProtocol just to hide the implementation of Array. Don't turn MyClass into MyClassProtocol. Ask what kinds of algorithms want to use types like this one.
When you find yourself creating interlocking hierarchies of types (subclasses of something that require subclasses of some other thing), you have often sliced the problem in the wrong direction. You should rethink whether you could slice the problem so that the varying parts of SomeBaseClass are actually part of MyClass (often this makes SomeBaseClass simpler; for example being pure data rather than having logic).
There's no one right answer here. It depends on the nature of MyClass, so we can't really discuss it in abstract terms. Like abstract classes, solving abstract problems often leads you down the wrong roads. It's often better to start with concrete types and then find their similarities and extract them.
Even with that said, it's worth showing what a simple, naive protocol would look like here. (It's possible this is even the correct protocol.)
public protocol MyProtocol {
var someProperty: SomeBaseClass { get }
}
That's it. That's all you actually express in your current abstract class (and it's not actually clear whether someProperty is public; if it's private, this protocol would be empty).
An implementing struct would then look like:
struct MyStruct: MyProtocol {
var someProperty: SomeBaseClass
}
Or if you wanted a reference type, you could use a final class:
final class MyClass: MyProtocol {
var someProperty: SomeBaseClass
init() {
someProperty = ...
}
}
Or if you wanted inheritance, you could use a non-final class:
class MyClass: MyProtocol {
var someProperty: SomeBaseClass
init() {
someProperty = ...
}
}

Inheritance in Class Vs Protocol

I am little bit messed up with the following concept:
Code 1 :
class New{
func abc(){
print("new class")
}
}
class ClassNew: New {
override func abc() {
print("derived class")
}
}
Code 2:
protocol New{}
extension New{
func abc(){
print("new protocol")
}
}
class ClassNew: New {
func abc() {
print("derived protocol")
}
}
What is the difference between Code 1 and Code 2 as both of them serves the same purpose?
In code 2, classNew is inheriting from new protocol or just conforming to the protocol?
Any Explanation will be highly appreciated!
Code 1 and code 2 are fundamentally not the same.
What is the difference between Code 1 and Code 2 as both of them serves the same purpose?
No they don't. The first one defines a class hierarchy, the second defines a protocol (an API, if you like) and a type that conforms to it.
In code 2, classNew is inheriting from new protocol or just conforming to the protocol?
It's conforming to the protocol. There's no inheritance involved (if you are being pedantic).
Code 1 defines a base class and a class that inherits from it. The subclass overrides the base class for the function abc() and it behaves as you would expect given a class hierarchy i.e.
let x: New = ClassNew()
let y: ClassNew = ClassNew()
print(x.abc()) // prints "derived class"
print(y.abc()) // prints "derived class"
Both print statements call the derived class's abc()
In code 2 you define a protocol with no methods, and an extension to the protocol with an extension method. Note that this is not a "default method" there is nothing in the protocol to default. You then define a class that conforms to the protocol and adds a new method that happens to have the same name as the extension method. The distinction (from the pure class hierarchy) is important because the version of abc() called is determined statically at compile time
protocol New2{}
extension New2{
func abc(){
print("new protocol")
}
}
class ClassNew2: New2 {
func abc() {
print("derived protocol")
}
}
let y2: ClassNew2 = ClassNew2()
let x2: New2 = y2
print(x2.abc()) // prints "new protocol"
print(y2.abc()) // prints "derived protocol"
Even though x2 and y2 are the same object different versions of the function are called. This is because the compiler is not allowed to assume anything about x2 except what it can infer from the protocol. So it doesn't know that the object has anabc() of its own so it must call the extension function.
If you had defined the protocol like this:
protocol New3{
func abc()
}
extension New3{
func abc(){
print("new protocol")
}
}
class ClassNew3: New3 {
func abc() {
print("derived protocol")
}
}
let y3: ClassNew3 = ClassNew3()
let x3: New3 = y3
print(x3.abc()) // prints "derived protocol"
print(y3.abc()) // prints "derived protocol"
This time the compiler knows that the object should have a function abc() and will only use the extension function if it doesn't. Then the normal inheritance rules for classes apply.
Code 2 is an example of protocol extensions. Big difference is that you can't call super.abc() in Code 2 — you have to provide a method implementation that is not in any super context.
Just my opinion — do not use protocol default implementation, as compiler won't save you if you forget to provide "override" when you really need one.
classNew is simply conforming to the protocol in the second code. This is true to every protocol in Swift as inheritance is not currently supported with protocols.
This also answers your first question: there is no significant difference between the two codes in this use case, but, generally speaking, a protocol is good for other kinds of things than subclassing.
Code 1 and Code 2 are exactly same, just conceptually different.
If we put it in simple words, a Class defines the object itself, and a Protocol defines the behaviour of the object.
If compared to Java, a protocol is similar to Interfaces.
Checkout the Protocol Documentation

Issue with the call hierarchy of a swift protocol extension

I've implemented a little wrapper for Alamofire's reachability. Now I ran into an issue with a subclass not receiving notifications.
As dfri added in a comment, the problem can be described as a superclass method invoked by a subclass instance does not see an overridden subclass method if it is placed in an extension.
Thanks for his excellent gist showing the reproducible problem with the usual foo/bar: https://gist.github.com/dfrib/01e4bf1020e2e39dbe9cfb14f4165656
The protocol & extension logic:
protocol ReachabilityProtocol: class {
func reachabilityDidChange(online: Bool)
}
extension ReachabilityProtocol {
func configureReachabilityManager() {
// triggered externally:
rechabilityManager?.listener = { [weak self] status in
self?.reachabilityDidChange(online)
}
}
func reachabilityDidChange(online: Bool) {
// abstract, implement in subclasses
}
}
Now ViewController A adopts this protocol and implements the method:
class A: UIViewController, ReachabilityProtocol {
func reachabilityDidChange(online: Bool) {
debugPrint("123")
}
}
Working until here, prints 123.
ViewController B is a subclass and overrides the method from A:
class B: A {
override func reachabilityDidChange(online: Bool) {
super.reachabilityDidChange(online)
debugPrint("234")
}
}
Working, too. Prints now 234 and 123 upon notification.
Now the tricky part, in terms of structuring the code, the overriden method got moved into an own extension inside of B (same swift file as class B):
class B: A {
...
}
// MARK: - Reachability Notification
extension B {
override func reachabilityDidChange(online: Bool) {
super.reachabilityDidChange(online)
debugPrint("234")
}
}
Now B's reachabilityDidChange() isn't called anymore. Output is just 123.
To check the logic I even tried to remove the override keyword: the compiler immediately complains about needing it.
So from what I can say the call hierarchy is correct. Visibility too.
Subsumption: If the method overridden is placed into it's own extension, it's not visible/invoked anymore but the compiler still requires the override keyword.
That's something I didn't came across yet, or it's me working to long on the same project today..
Any hints?
Overriding superclass methods in extensions: only allowed for Objective-C compatible methods
First of all we note that you can only override a superclass method in an extension of a subclass if the method is Objective-C compatible. For classes deriving from NSObject, this is true for all instance methods (which is true here, as UIViewController derives from NSObject). This is covered in e.g. the following Q&A:
Can you override between extensions in Swift or not? (Compiler seems confused!)
Enforcing dynamic dispatch via Objective-C runtime
Now, from Interoperability - Interacting with Objective-C APIs - Requiring Dynamic Dispatch, we note the following
When Swift APIs are imported by the Objective-C runtime, there are no
guarantees of dynamic dispatch for properties, methods, subscripts, or
initializers. The Swift compiler may still devirtualize or inline
member access to optimize the performance of your code, bypassing the
Objective-C runtime.
You can use the dynamic modifier to require that access to members be
dynamically dispatched through the Objective-C runtime.
Moreover, from The Language Ref. - Declarations - Declaration Modifyers we read
dynamic (modifier)
Apply this modifier to any member of a class that can be represented
by Objective-C. When you mark a member declaration with the dynamic
modifier, access to that member is always dynamically dispatched using
the Objective-C runtime. Access to that member is never inlined or
devirtualized by the compiler.
Because declarations marked with the dynamic modifier are dispatched
using the Objective-C runtime, they’re implicitly marked with the objc
attribute.
Enforcing dynamic dispatch for reachabilityDidChange(...) in A
Hence, if you add the dynamic modifier to method reachabilityDidChange(...) in your superclass A, then access to reachabilityDidChange(...) will always be dynamically dispatched using the Objective-C runtime, and hence find and make use of the correct overridden reachabilityDidChange(...) method in the class B extension, for instances of B. Hence,
dynamic func reachabilityDidChange(online: Bool) { ... }
in A will fix the above.
Below follows a more minimal example of your issue above, redeemed by demanding dynamic dispatch via obj-c runtime for method foo() in class A (equivalent to your method reachabilityDidChange(...) in class A).
import UIKit
protocol Foo: class {
func foo()
}
extension Foo {
func foo() { print("default") }
}
class A: UIViewController, Foo {
dynamic func foo() { print("A") } // <-- note dynamic here
func bar() { self.foo() }
/* \
hence, foo() is dynamically dispatched here, and for
instances where "self === B()", this is correctly
resolved as the foo() in the extension to B */
}
class B : A { }
extension B {
override func foo() {
super.foo()
print("B")
}
}
let a = A()
a.bar() // A
let b = B()
b.bar() // A B
/* or, only "A" if not using dynamic dispatch */

Using some protocol as a concrete type conforming to another protocol is not supported

I’m trying to mix generics with protocols and I’m getting a really hard time xD
I have certain architecture implemented in an Android/Java project, and I’m trying to rewrite it to fit it in a swift/iOS project. But I’ve found this limitation.
ProtocolA
protocol ProtocolA {
}
ProtocolB
protocol ProtocolB : ProtocolA {
}
ImplementProtocolA
class ImplementProtocolA <P : ProtocolA> {
let currentProtocol : P
init(currentProtocol : P) {
self.currentProtocol = currentProtocol
}
}
ImplementProtocolB
class ImplementProtocolB : ImplementProtocolA<ProtocolB> {
}
So, when I try to set ProtocolB as the concrete type that implements ProtocolA, I get this error:
Using 'ProtocolB' as a concrete type conforming to protocol 'ProtocolA' is not supported
1 Is there any reason for this “limitation”?
2 Is there any workaround to get this implemented?
3 Will it be supported at some point?
--UPDATED--
Another variant of the same problem, I think:
View protocols
protocol View {
}
protocol GetUserView : View {
func showProgress()
func hideProgress()
func showError(message:String)
func showUser(userDemo:UserDemo)
}
Presenter protocols
protocol Presenter {
typealias V : View
}
class UserDemoPresenter : Presenter {
typealias V = GetUserView
}
Error:
UserDemoPresenter.swift Possibly intended match 'V' (aka
'GetUserView') does not conform to 'View’
What is that?? It conforms!
Even if I use View instead of GetUserView, it does not compile.
class UserDemoPresenter : Presenter {
typealias V = View
}
UserDemoPresenter.swift Possibly intended match 'V' (aka 'View') does
not conform to 'View'
xxDD I don’t get it, really.
--UPDATED--
With the solution proposed by Rob Napier the problem is not fixed, instead, it is just delayed.
When a try to define a reference to UserDemoPresenter, I need to specify the generic type, so I get the same error:
private var presenter : UserDemoPresenter<GetUserView>
Using 'GetUserView' as a concrete type conforming to protocol
'GetUserView' is not supported
The underlying reason for the limitation is that Swift doesn't have first-class metatypes. The simplest example is that this doesn't work:
func isEmpty(xs: Array) -> Bool {
return xs.count == 0
}
In theory, this code could work, and if it did there would be a lot of other types I could make (like Functor and Monad, which really can't be expressed in Swift today). But you can't. You need to help Swift nail this down to a concrete type. Often we do that with generics:
func isEmpty<T>(xs: [T]) -> Bool {
return xs.count == 0
}
Notice that T is totally redundant here. There is no reason I should have to express it; it's never used. But Swift requires it so it can turn the abstract Array into the concrete [T]. The same is true in your case.
This is a concrete type (well, it's an abstract type that will be turned into a concrete type any time it's instantiated and P is filled in):
class ImplementProtocolA<P : ProtocolA>
This is a fully abstract type that Swift doesn't have any rule to turn into a concrete type:
class ImplementProtocolB : ImplementProtocolA<ProtocolB>
You need to make it concrete. This will compile:
class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {}
And also:
class UserDemoPresenter<T: GetUserView> : Presenter {
typealias V = T
}
Just because you're likely to run into the issue later: your life will go much easier if you'll make these structs or final classes. Mixing protocols, generics, and class polymorphism is full of very sharp edges. Sometimes you're lucky and it just won't compile. Sometimes it will call things you don't expect.
You may be interested in A Little Respect for AnySequence which details some related issues.
private var presenter : UserDemoPresenter<GetUserView>
This is still an abstract type. You mean:
final class Something<T: GetUserView> {
private var presenter: UserDemoPresenter<T>
}
If that creates a problem, you'll need to create a box. See Protocol doesn't conform to itself? for discussion of how you type-erase so that you can hold abstract types. But you need to work in concrete types. You can't ultimately specialize on a protocol. You must eventually specialize on something concrete in the majority of cases.

Swift protocol allows unimplemented function when it exists in base class

Assume the below playground:
protocol MyProtocol
{
func MyFunc()
}
class MyBase : MyProtocol
{
func MyFunc()
{
}
}
class MyClass : MyBase, MyProtocol
{
}
I was expecting this to not compile, and nag about not implementing my protocol. But unlike other languages, Swift seems to think its fine if the protocol conforms to the base class.
How can I get MyClass to force my method to be overridden?
I'm using Swift 1.1, tia.
Your code is definitely valid. MyClass inherits from MyBase which already conforms to MyProtocol, so having the subclass also conform to it is completely redundant. That being said, you are basically looking for an abstract function which does not really exist in Swift, the closest I think you can get to achieving what you want is recommended in this answer. So in your base class just give a warning if not overriden:
class MyBase : MyProtocol {
func MyFunc() {
fatalError("This method must be overridden")
}
}
As recommended in the question comments, a different approach may work better for what you are attempting to do (e.g. composition or using a struct), but it is a bit hard to recommend a different solution without knowing more about what you are trying to achieve (rather than just the expected solution). If you do provide additional details you may receive a more suitable answer.