How to implement "abstract" property initializers in Swift - 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 = ...
}
}

Related

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

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.

Swift Implicitly pass self as inout parameter for reference type

Is it possible to implicitly pass self as an inout parameter to modify a reference variable in place?
Here is a method which can convert an abstract base class into one of its concrete subclasses. My question is, must I always have that first argument, obj: inout AbstractBaseClass, or can I implicitly pass self. I realize that this might also be expressed as a static method.
func convertTo(_ obj: inout AbstractBaseClass, _ type: ConcreteClassTypes) {
switch type {
case .concreteClass1: obj = ConreteClass1()
case .concreteClass2: obj = ConcreteClass2()
}
}
Here is the full code:
class AbstractClass {
enum ConcreteType {
case concreteClass1
case concreteClass2
}
var id: Int = 0
fileprivate init() { }
func convert(_ obj: inout AbstractClass, to type: ConcreteType) {
let oldId = obj.id
switch type {
case .concreteClass1: obj = ConcreteClass1()
case .concreteClass2: obj = ConcreteClass2()
}
obj.id = oldId
}
class ConcreteClass1: AbstractClass {
override init() { super.init() }
}
class ConcreteClass2: AbstractClass {
override init() { super.init() }
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(&obj, to: .concreteClass2) //is there any way to eliminate this first argument?
Like matt, I'm not convinced that inout is the right tool for the job in this case.
Although that being said, if you insist on it, one way to achieve what you want is to (ab)use protocol extensions. They allow the definition of mutating methods, which pass the implicit self parameter as inout (to allow the mutation of adopting value types).
So you could say:
protocol AbstractClassProtocol {}
class AbstractClass : AbstractClassProtocol {
enum ConcreteType {
case concreteClass1
case concreteClass2
}
fileprivate init() {}
class ConcreteClass1: AbstractClass {
override init() { super.init() }
}
class ConcreteClass2: AbstractClass {
override init() { super.init() }
}
}
extension AbstractClassProtocol where Self == AbstractClass {
mutating func convert(to type: AbstractClass.ConcreteType) {
switch type {
case .concreteClass1:
self = AbstractClass.ConcreteClass1()
case .concreteClass2:
self = AbstractClass.ConcreteClass2()
}
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(to: .concreteClass2)
print(obj) // AbstractClass.ConcreteClass2
But it's a bit of a hack, and I'd be wary about using it.
...to modify a reference variable in place? Here is a method which can convert an abstract base class into one of its concrete subclasses...
You are not "modifying" or "converting" anything. You are substituting one object for another. Thus, there is no self that could be passed here; the idea of what you are doing is to destroy one self and provide another in its place.
That said, it's a little unclear what the inout variable is for. Why don't you just assign the new object in place of the old object?
func giveMeA( _ type: AbstractClass.ConcreteType) -> AbstractClass {
switch type {
case .concreteClass1: return AbstractClass.ConcreteClass1()
case .concreteClass2: return AbstractClass.ConcreteClass2()
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj = giveMeA(.concreteClass2)
The effect is identical to what you're doing. If you think it's not, you're just kidding yourself about what the inout parameter is doing.
I'm going to propose a completely different way of looking at what you're trying to do.
Don't have an abstract superclass. Don't have multiple subclasses. Have one class with multiple functional variants. The functional variants are expressed by a helper object — a struct — owned by the class instance.
So to change functionalities, you just set the helper to a different type of helper. Basically, you give your object a personality transplant.
I have an app that works that way. I have four view controllers that present slightly different info in slightly different ways. But in fact they are one view controller and an enum with four cases that dictates those differences. Thus, at any time the view controller can manifest itself as any of the four types.

Swift generic reference type

I'm having issues trying to constrain generic type requirements to just reference types. Here's some example code:
class WeakHolder<Element: AnyObject> {
weak var element: Element?
init(element: Element) {
self.element = element
}
}
protocol Animal: class { }
class Dog: Animal { }
let dog: Animal = Dog()
let holder = WeakHolder<Animal>(element: dog) // Error: Using "Animal" as a concrete type conforming to protocol 'AnyObject' is not supported.
If I change the generic requirement to <Element: class>, I get the error class constraint can only appear on protocol declarations.
Is this a limitation of generics? Marking a protocol as class is enough to have a weak reference to that protocol, is there no equivalent in generics?
The simple answer is that you cannot have a generic type that is a protocol.
Writing out the syntax makes it clear how this works:
class/struct GenericType<TypeName: TypeConstraints> {}
let thing = GenericType<Type>() where Type is a class or struct that adheres to any constraints
A Protocol Requiring adopting Types to be a class means any adopters are classes, but the Protocol itself is still not a Type.
It's possible generics could at some point support protocols, but it would require changing the general approach to either protocols or generics. Though your specific example may be possible with a smaller amount of work behind the scenes, so it's possible this may be implemented at some point.
You can take a look at The Generics Manifesto if you want to see the direction they're going. Skimming it I didn't find anything directly related to your use case, but it's fairly specific so it may not be included in the parameters of the document.
Another solution that worked in my particular case is the following:
class WeakHolder<Element: AnyObject> {
weak var element: Element?
init(element: Element) {
self.element = element
}
}
protocol Animal: class { }
class Dog: Animal { }
let dog: Animal = Dog()
let holder = WeakHolder<AnyObject>(element: dog as AnyObject)
When accessing element, I simply need to perform a downcast back to my protocol. Of course, I'll lose compile time safety when using this class with value types, but that's a non-issue in my situation.

Why doesn't a class have to provide a failable initializer if it implements a protocol that declares one?

I am trying to understand the following, contrived, example:
protocol MyProtocol {
init?(string: String)
}
class MyObject: MyProtocol {
let s: String
required init(string: String) {
self.s = string
}
}
let o = MyObject(string: "test")
print(o.s)
MyProtocol declares a failable initializer. MyObject conforms to MyProtocol and the example code compiles and executes without issue.
My question is: Why doesn't MyObject have to provide a failable initializer (as per MyProtocol)?
This is for the same reason that this compiles:
class A {
init?(s:String) {}
init() {}
}
class B : A {
override init(s:String) {super.init()}
}
init can override (i.e. be substituted for) init?.
See also the docs (when something is so clearly documented, it seems silly to ask "why"; it's just a fact about the language):
A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type.
(As pointed out in the comments on the question and on the answer, this makes perfect sense if you think about the difference between an init? that happens never to fail and an init with the same signature — namely, there is no effective difference. To put it another way: You can tell me that I may fail, but you cannot tell me that I must fail.)

whats the swift equivalent of NSObject<Protocol>?

I have a class that needs to be set with a variable of a NSObject subclass and that implements a certain protocol.
protocol ProtoTest {
var foo: Int { get set }
}
class AClass: NSObject, ProtoTest {
var foo: Int = 3
}
class BClass: NSObject, ProtoTest {
var foo: Int = 4
}
class Consumer {
var protoInstance: ProtoTest? //Does not cary any information of the class just the protocol
var protoInstance2: protocol<NSObjectProtocol, ProtoTest>?
init(x: ProtoTest) {
self.protoInstance = x
self.protoInstance2 = nil
}
init(x: protocol<NSObjectProtocol, ProtoTest>) {
self.protoInstance2 = x
self.protoInstance = nil
}
func doSomething() {
if let x = protoInstance {
x.copy() //'ProtoTest' does not have a member named 'copy'
}
if let x = protoInstance2 {
x.copy() //protocol<NSObjectProtocol, ProtoTest> does not have a member named 'copy'
}
}
}
In the example above, neither declarations of the variable are gonna work. since neither of them have any knowledge of a base class?
How do I implement this in swift ?
The usual equivalent of NSObject<Protocol> in Swift is simply Protocol. Typically, this protocol is declared as a class protocol to guarantee that it will be adopted by a class.
If you also need the NSObject protocol methods (such a respondsToSelector:, then make Protocol adopt NSObjectProtocol.
If the problem is merely that you want to call copy() and you can't persuade the compiler to let you do it, then adopt NSCopying as well (or just use respondsToSelector: and performSelector: to bypass the compiler altogether).
You can do this a couple of ways. First, you can make Consumer generic:
class Consumer<T: NSObject where T: Prototest> {
var protoInstance: T?
var protoInstance2: T?
}
If you do that, then all references to protoInstance or protoInstance2 will inherit from NSObject, and you will be able to call methods like .copy() directly on the object.
If you don't want Consumer to be generic, you can enforce restraints on the init methods using generic parameters, like this:
class Consumer {
// ...
init<T: NSObject where T: Prototest>(x: T) {
protoInstance = x
}
}
If you do that, you will be guaranteed that protoInstance will be an NSObject, but you will have to cast to NSObject to use any of NSObject's methods:
func doSomething() {
if let x = protoInstance as? NSObject {
x.copy()
}
}
Edit:
Note that I wasn't sure if you really wanted protoInstance and protoInstance2 to be of different types I was a little unclear from your question. If you do want them to be different types, I can add additional suggestions to this answer.