type A requires that type B be a class type swift 4
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))
}
}
Pass a class type for use inside a method
How about the generic Swift way.
The code constrains the generic type T
to MyClass
since it must have a name
property.
class MyClass : NSObject {
var name : String
override required init() {
self.name = ""
super.init()
}
}
class OneClass : MyClass {
required init() {
super.init()
self.name = "One"
}
}
class TwoClass : MyClass {
required init() {
super.init()
self.name = "Two"
}
}
class Thing : NSObject {
func doStuff<T : MyClass>(withClass cls: T.Type) -> String {
let x = cls.init()
return x.name
}
}
let z = Thing()
print(z.doStuff(withClass: OneClass.self))
print(z.doStuff(withClass: TwoClass.self))
Or use a protocol.
protocol Nameable {
var name : String { get }
init()
}
class MyClass : NSObject, Nameable { ...
...
class Thing : NSObject {
func doStuff<T : Nameable>(withClass cls: T.Type) -> String {
let x = cls.init()
return x.name
}
}
How to make protocol conformed by only required classes?
I am not sure if below code is what you need, do let me know if that’s what you were looking for, else I will be happy to remove my answer.
protocol A:BaseViewController {
func execute()
}
protocol B:A {
func confirm()
}
class BaseViewController: UIViewController {
}
class AnotherVC: B {
}
In above code compiler will give error saying-:
'A' requires that 'AnotherVC' inherit from ‘BaseViewController'
Once you inherit AnotherVC
from BaseViewController
, it will give another error saying-:
Type 'AnotherVC' does not conform to protocol ‘A'
Once you confirm the implementations errors will be resolved-:
class AnotherVC:BaseViewController, B {
func confirm() {
}
func execute() {
}
}
Type specific method is unavailable for a var returned with `some` directive
The return type of the method is some TransportProtocol
, not Car
. So even though the returned instance is of type Car
, you cannot call any methods on it that only exist on Car
, but not on TransportProtocol
.
The runtime knows that the concrete type of someTransport
is Car
, but the compiler only knows that the return type conforms to TransportProtocol
.
If you want to be able to access Car
methods on someTransport
, you need to downcast it to Car
.
if let car = someTransport as? Car {
car.changeOil()
}
Using the some
keyword has type-system benefits when used for opaque returns types (introduced in SE-0244 as part of Swift 5.1), since it actually enables returning a protocol with associated types without having to explicitly make the method generic. This is what drives SwiftUI, since it enables you to return some View
.
On the other hand, using opaque return types for protocols without associated types holds no benefits, so in your particular example, there's no reason to use it.
Why using Self as return type is not considered as the protocol's constraint?
Because it's not useful to have a Self
as a parameter type of a method. Suppose that you can do:
protocol P {
func f(_ x: Self)
}
class A: P {
func f(_ x: Self) {
// not relevant
}
}
class B: A { }
Now suppose I have:
func g(x: A) {
// what can I do with x?
}
The fact is, there is no way to call x.f
. Because I can pass an instance of B
to x
, in which case x.f
would accept a B
instead. x
could be an instance of any subclass of A
that I have no way of knowing at compile time, so I don't know what I can pass to x.f
.
Compare that to Self
used as the return type:
protocol P {
func f() -> Self
}
// Implementation:
class A: P {
func f() -> Self {
self
}
}
class B: A { }
func g(x: A) {
let foo: A = x.f()
}
Here, we know that I can at least assign the return value of x.f
to a variable of type A
. Even if x
is an instance of B
, which means that f
returns a B
, we can still assign that to a variable of type A
.
Related Topics
Need Explanation About Random Function Swift
Using Foreach with a String Array - [String] Has No Member 'Identified'
Is There a Way I Can Combine a Geofirestore Query with a Normal Firestore Query
Swift Generics: Non-Nominal Type Does Not Support Explicit Initialization
How to Create and Access Share App Group Document Directory
Dynamic Datasource/Delegates for Uitableview in Swift
Swift: For-In Loop Requires '[Deepspeechtokenmetadata]' to Conform to 'Sequence'
Convert [(Key: String, Value: String)] in [String:String]
Swift: Uploading Image to Firebase Cloud Storage When User Closes App
How to Set a Function as Function Argument in Swift 3
Failed to Obtain a Cell from Its Datasource with Swift 3
How to Compare Result to .Succeed in Swift
How to Use View Controller (Calendarkit) in Swiftui Application
Alternative to Switch Statement in Swiftui Viewbuilder Block