Inheriting a class that conforms to a protocol - swift

I can not figure out why Xcode playground is crashing, here is my basic setup
protocol Shootable {
func shoot()
}
class BaseMissile: Shootable {
var damage = 0
func shoot() {
println("Pew pew for \(damage) damage")
}
}
class Missile1: BaseMissile {
override init() {
super.init()
damage = 1
}
}
protocol Targetable {
var life: Int {get set}
}
class BaseSpaceship: Targetable {
var life = 0
var currentMissile: BaseMissile!
func printHealth() {
println("My current life: \(life)")
}
}
class Spaceship1: BaseSpaceship {
override init() {
super.init()
life = 1
currentMissile = Missile1()
}
}
var spaceship = Spaceship1()
spaceship.printHealth()
spaceship.currentMissile.shoot()
specifically the last line spaceship.currentMissile.shot() crashes the playground. If I move var currentMissile: BaseMissile! from BaseSpaceship to Spaceship1 it works, but is that an acceptable way to handle this?

I guess this happens because BaseSpaceship class has no initializers and var currentMissile: BaseMissile! cant be nil. So you either should do it optional by replacing ! with ? or give it a default value.

Related

How can I get a specific struct type returned?

I want to initialize the struct by receiving the "struct type"(?) by a specific logic as below.
As I abstracted the return value of the struct into MyProtocol had a declaration of init(), which seems a little awkward.
I'm not sure I can do this.
I'd like to get an undecided struct type returned, what should I do?
Is this for the best?
For your information, Opaque Type is not available because it needs to support iOS 13 or earlier.
protocol MyProtocol {
init() // Is this for the best?
}
struct AAA: MyProtocol {
var numberAAA: Int // Sample variable.
init() {
print("init AAA")
numberAAA = 100
}
}
struct BBB: MyProtocol {
var numberBBB: Int // Sample variable.
init() {
print("init BBB")
numberBBB = 200
}
}
class MyClass {
func mainLogic() {
let myStruct = randomStruct()
myStruct.init() // This is the reason init () declared in the MyProtocol.
}
func randomStruct() -> MyProtocol.Type {
if Bool.random() {
return AAA.self
} else {
return BBB.self
}
}
}
init() as a protocol requirement seems odd. No one is stopping you to do this and compiler should allow this, however I would consider making protocol based on some other requirement rather than just init().
Here's an attempt to do so -
protocol NumberOperation {
var number: Int { get set }
mutating func perform()
}
struct Incrementer: NumberOperation {
var number: Int
mutating func perform() {
number += 1
}
}
struct Decrementer: NumberOperation {
var number: Int
mutating func perform() {
number -= 1
}
}
struct Record<O: NumberOperation> {
public var operation: O
mutating func perform() {
operation.perform()
}
}
class MyClass {
func mainLogic() {
var record = getRecord(type: Incrementer.self)
record.perform()
}
func getRecord<O: NumberOperation>(type: O.Type) -> Record<O> {
if type == Incrementer.self {
return Record(operation: Incrementer(number: 1) as! O)
}
return Record(operation: Decrementer(number: 10) as! O)
}
}
This introduces a container type Record that holds/wraps our type based on the same protocol conformation. This does the same what you were doing, probably is easier to read/understand.

How to handle multi-inheritance in Swift?

This is probably 2 swift questions in one...
How do I solve a situation where I want to extend an existing base class (UIView in my case) with functionality that requires stored properties? ...so that I can reuse the code for other classes?
I have tried to solve it through composition below, but I don't know if there is a more obvious way that I just can't see as I am fairly new to swift...
The second question:
In my implementation I have an abstract class ManagedComponentImpl which needs an eventReceiver object which is going to be the containing UIView subclass.
The problem I have with my implementation is that swift forces me to define an object binding where Receiver:NSObject for ManagedComponentImpl, so that I can declare the optional variable eventReceiver as weak. (and I guess I would create a memory leak otherwise). However I would want to use this implementation on a variety of objects (which could of course all inherit NSObject, but they do not actually need to for other reasons but this, so it seems odd). So question number 2: Is there a way to avoid this?
EDIT: And yes! I made a mistake mixing model and view code here, but I guess the fundamental problem remains when you switch UIViewController for UIView :-)
public protocol ManagedConnection {
var connectionKey:String { get set }
}
public protocol ManagedComponent: ConnectionObserver {
var connectionKey:String { get set }
func connectTo()
func disconnectFrom()
}
public protocol EventReceiver: ConnectionObserver {
var variableSet:Set<VariableID>? { get }
var handleVariableUpdates: ((Set<VariableID>)->Void)? { get }
}
class ManagedComponentImpl<Receiver: EventReceiver> where Receiver:NSObject {
public var _connectionKey: String = Shared
//The connection Key
public var connectionKey: String
{
set {
disconnectFrom()
self._connectionKey = newValue
connectTo()
}
get {
return _connectionKey
}
}
// The varset needed by this control
weak var eventReceiver:Receiver!
// handler for the status pane variables
//
var connectionObserverHandlerID:UInt16 = 0
var eventHandlerID:UInt16 = 0
public init(receiver:Receiver) {
self.eventReceiver = receiver
}
public func connectTo() {
guard let manager = Connections.shared[self.connectionKey] else { return }
let connection = manager.connection
// disconnect any previous connections
disconnectFrom()
// Connect the connection observer
connectionObserverHandlerID = connection.addConnectionObserver(observer: eventReceiver)
if let variableSet = eventReceiver.variableSet, let handler = eventReceiver.handleVariableUpdates {
eventHandlerID = connection.requestVariables(variables: variableSet, handler: handler)
}
}
public func disconnectFrom(){
guard let manager = Connections.shared[self.connectionKey] else { return }
let connection = manager.connection
// Disconnect
if connectionObserverHandlerID != 0 {
connection.removeConnectionObserver(id: connectionObserverHandlerID)
}
if eventHandlerID != 0 {
connection.unRequestVariables(ident: eventHandlerID)
}
}
}
class ManagedUIView: UIView, ManagedComponent, EventReceiver {
private var component:ManagedComponentImpl<ManagedUIView>!
public var variableSet:Set<VariableID>?
public var handleVariableUpdates:((Set<VariableID>)->Void)?
public override init(frame: CGRect) {
super.init(frame: frame)
component = ManagedComponentImpl<ManagedUIView>(receiver: self)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
component = ManagedComponentImpl<ManagedUIView>(receiver: self)
}
var connectionKey:String {
set {
component.connectionKey = newValue
}
get {
return component.connectionKey
}
}
func connectTo() {
component.connectTo()
}
func disconnectFrom() {
component.disconnectFrom()
}
func notifyState(state: ConnectionState) {}
}
Okay - for everybody reading this, the answers are:
- The problem should probably be solved by a delegate and not by inheritance.
- To avoid inheriting from NSObject: the problem seems to be that protocols can not only be implemented by classes. Therefore the protocol needs a class limitation to work as weak references. As a result ManagedComponentImpl does not need to be generic any more and I can just have a weak CAPEvent receiver optional.

type A requires that type B be a class type swift 4

the following code gives me a compile error
'WeakReference' requires that 'ServiceDelegate' be a class type
protocol ServiceDelegate: AnyObject {
func doIt()
}
class SomeClass() {
// compile error occurs in this line
private var observers = [WeakReference<ServiceDelegate>]()
}
WeakReference code:
final class WeakReference<T: AnyObject> {
private(set) weak var value: T?
init(value: T?) {
self.value = value
}
}
How can I fix this error? Delegate should be declared correctly as per this site.
What I have tried so far:
Changing the delegate protocol conformance from AnyObject to
class does not solve the problem.
Try the above code in a clean playground.
You can't have a WeakReference<ServiceDelegate>. ServiceDelegate itself is not an AnyObject, it just requires that anything that conforms to it be an AnyObject.
You would need to make SomeClass generic and use the generic type as the type for the WeakReference:
class SomeClass<T: ServiceDelegate> {
private var observers = [WeakReference<T>]()
}
If the generic on SomeClass is too constricting and you want to be able to have instances of multiple unrelated classes as observers then I would do it by abandoning the generic parameter on WeakReference:
final class WeakServiceDelegate {
private(set) weak var value: ServiceDelegate?
init(value: ServiceDelegate?) {
self.value = value
}
}
class SomeClass {
private var observers = [WeakServiceDelegate]()
}
Alternatively you could make WeakReference conditionally conform to ServiceDelegate:
extension WeakReference: ServiceDelegate where T: ServiceDelegate {
func doIt() {
value?.doIt()
}
}
And then use an array of ServiceDelegate in SomeClass:
class SomeClass {
private var observers = [ServiceDelegate]()
func addObserver<T: ServiceDelegate>(_ observer: T) {
observers.append(WeakReference(value: observer))
}
}
As you see, ServiceDelegate is a protocol, not a class type.
Even if all types which can conform to ServiceDelegate are class types, ServiceDelegate itself is not a class type. It is the fact of the pure Swift protocols currently.
Try #obc, Objective-C protocols are a bit different:
#objc protocol ServiceDelegate {
func doIt()
}
You may want to exclude Objective-C something and to make some pure Swift classes conform to ServiceDelegate, but I cannot find other ways around.
The problem is that WeakReference<ServiceDelegate> is wrong at line
private var observers = [WeakReference<ServiceDelegate>]()
You have to use a concrete class instead of protocol inside <>
You have two possible solutions:
Create a concrete class and use it:
class ServiceClass: ServiceDelegate {
//...
}
private var observers = [WeakReference<ServiceClass>]()
Or use a protocol. I mean this:
final class WeakReference<T: AnyObject> {
private(set) weak var value: T?
init(value: T?) {
self.value = value
}
}
protocol SomeContainer: AnyObject { }
extension WeakReference: SomeContainer { }
and use this way:
private var observers = [SomeContainer]()
Note
Using this way:
class SomeClass<T: ServiceDelegate> {
private var observers = [WeakReference<T>]()
}
You just move the problem to another part of the code.
I had similar problem and ended up keeping generic WeakReference, but removing type constraint:
struct WeakReference<T> {
private weak var storage: AnyObject?
var value: T? {
get { return storage.map { $0 as! T } }
set {
storage = newValue.map { $0 as AnyObject }
}
}
init(value: T?) {
self.value = value
}
}
This works for classes, Objective-C protocols and Swift protocols:
protocol P: class {}
#objc protocol Q {}
class Z: P, Q {}
var z = Z()
var rz = WeakReference<Z>(value: z)
var rp = WeakReference<P>(value: z)
var rq = WeakReference<Q>(value: z)
assert(rz.value === z)
assert(rp.value === z)
assert(rq.value === z)
z = Z()
assert(rz.value === nil)
assert(rp.value === nil)
assert(rq.value === nil)
Unfortunately it compiles for other things too:
protocol R {}
struct S: R {}
var rr = WeakReference<R>(value: S())
print("rr =", rr.value as Any) // nil
var rs = WeakReference<S>(value: S())
print("rs =", rs.value as Any) // nil
In Swift anything can be casted to AnyObject, but for value types that means boxing - new instance is allocated and immediately lost, so it always produces nil.
This can be used to implement an assertion that casting to AnyObject preserves identity:
struct WeakReference<T> {
private weak var storage: AnyObject?
var value: T? {
get { return storage.map { $0 as! T } }
set {
storage = newValue.map {
let asObject = $0 as AnyObject
assert(asObject === $0 as AnyObject)
return asObject
}
}
}
init(value: T?) {
self.value = value
}
}
Alternative approach would be to use https://github.com/wickwirew/Runtime to validate kind of T.self.
create plain protocol
public protocol AnyWeakValue {
var anyValue: Any? { get }
}
inherit associatedtype protocol from AnyWeakValue
public protocol WeakValue: AnyWeakValue {
associatedtype ValueType
var value: ValueType? { get }
}
extension WeakValue {
public var anyValue: Any? { return value }
}
create class Weak inherit WeakValue
open class Weak<Value: AnyObject>: WeakValue {
public init(value: Value?) { self.value = value }
open private(set) weak var value: Value?
}
using example
private var _delegates: [AnyWeakValue] = []
public var delegates: [SomeProtocol] {
return _delegates.compactMap({$0.anyValue as? SomeProtocol})
}
public func register<Delegate>(_ delegate: Delegate) where Delegate: SomeProtocol {
let weak: Weak<Delegate> = Weak.init(value: delegate)
_delegates.append(weak)
}

How to initialize variables inside subclasses' initializer that will be used in the super class's initializer?

In the following code, my intention is to have repeatNum declared in the base class because it is used in the base class (inside init and other functions). And each subclass should set repeatNum because only the subclass knows its own value.
class Base {
var repeatNum: Int
init() {
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
repeatNum = 10
super.init()
}
}
class SubClass2 : Base {
override init() {
repeatNum = 5
super.init()
}
}
Of course, it prompts some errors:
For the base class:
'self.repeatNum' not initialized
Return from initializer without initiating all stored properties.
For the subclasses:
use of 'self' in property access 'repeatNum' before super.init initializes self
I know I can simply call super.init() before setting repeatNum in the subclasses, but I really need to use repeatNum inside the base's init() in the real case. It becomes a paradox for me here somehow.
I also understand I can change the design to make the errors go away, but I am wondering if it's possible to achieve my original intention with some tweaks? I probably miss something here.
Your current code doesn't even compile, does it? It should complain about trying to use repeatNum before being initialized...
Maybe something like this could be an option for you?
class Base {
var repeatNum: Int
init(repeatNum: Int) {
self.repeatNum = repeatNum
for _ in 0..<repeatNum {
print("*")
}
}
}
class SubClass1 : Base {
init() {
super.init(repeatNum: 10)
}
}
class SubClass2 : Base {
init() {
super.init(repeatNum: 5)
}
}
i don't know what is you want,the following code is that ok
class Base {
var repeatNum: Int?
init() {
}
func printyourneed(){
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
super.init()
self.repeatNum = 10
self.printyourneed()
}
}
class SubClass2 : Base {
override init() {
super.init()
self.repeatNum = 5
self.printyourneed()
}
}
or
class Base {
var _repeatNum:Int?;
var repeatNum: Int?{
get{
return _repeatNum
}
set{
_repeatNum = newValue
printyourneed()
}
}
init() {
}
func printyourneed(){
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
super.init()
self.repeatNum = 10
}
}
class SubClass2 : Base {
override init() {
super.init()
self.repeatNum = 5
}
}

How to override private var in superclass

So I have the following superclass:
class Vehicle {
private var _maxSpeed: Int = 100
var maxSpeed: Int {
get {
return _maxSpeed
}
var tooFast: Bool {
get {
if maxSpeed >= 140 {
return false
} else {
return true
}
}
}
}
Plus I have some subclasses in which I want to override maxSpeed... per example:
class SuperCar: Vehicle {
//override the maxspeed...
}
But how should I approach this? Or is this only possible if we don't make it private? I tried to throw the private part out of the window but that won't work as well...
class Vehicle {
var maxSpeed: Int = 100
var tooFast: Bool {
get {
if maxSpeed >= 140 {
return false
} else {
return true
}
}
}
}
class SuperCar: Vehicle {
// override the maxSpeed...
override var maxSpeed: Int = 200
// Will not work...
}
Just put the class and subclass in the same file. private has nothing to do with inheritance. It has to do with file scope. Anything in the same file has access to private members.
That said, you almost certainly shouldn't be using inheritance here. Vehicle should almost certainly be a protocol. Then you wouldn't have any of the headaches of inheritance or private.
protocol Vehicle {
var maxSpeed: Int {get}
}
extension Vehicle {
// Default implementation if none is given
var maxSpeed: Int { return 100 }
// Another method that applies to all Vehicles
var tooFast: Bool {
return maxSpeed < 140 // (feels like this should be >= 140, but matching your code)
}
}
struct SuperCar: Vehicle {
// override the default implementation for the protcocol
var maxSpeed = 200
}
Set your private member variables in the init method
class Vehicle{
private var maxSpeed: Int
init(maxSpeed: Int = 100){
self.maxSpeed = maxSpeed
}
}
class SuperCar: Vehicle {
override init(maxSpeed: Int = 200){
super.init(maxSpeed: maxSpeed)
}
}
For a Swift 3 version of Rob's answer, you can't override private, but interestingly you can with fileprivate computed properties. You have to put the class in the same file though.
I did this today:
protocol Renderer {
}
class BaseClass {
private let _renderer: Renderer = BaseClassRenderer()
fileprivate var renderer: Renderer {
return _renderer
}
}
class Subclass: BaseClass {
private let _renderer: Renderer = SubclassRenderer()
override fileprivate var renderer: Renderer {
return _renderer
}
}
you can override computed property
class C {
var a: Int { return 10 }
}
class D:C {
override var a: Int { return 100 }