Reputation: 3501
I want to check whether a generic type conforms to a protocol. If it is, I need to cast the type itself and call a static method against it.
func log<T>(object: T) {
if let C = T as? Loggable { // this line doesn't compile
print("\(C.description(of: object))")
} else {
print("\(object)")
}
}
Anybody knows if it's doable?
UPDATE
I confused you with my first code snippet. Hopefully, second makes more sense. I've made some changes thanks to the @portella's answer, but it's still not enough.
func decodeObject<T>() -> T? {
guard let object = objects.first else {
return nil
}
objects.removeFirst()
if object is NSNull {
return nil
}
if T.self is Coding.Type { // the condition is fixed, thanks to @Hiron
if let data = object as? Data {
return type(of: (T.self as! Coding)).from(data: data) as? T
} else {
return nil
}
}
return object as? T
}
Upvotes: 0
Views: 3307
Reputation: 3501
Let's say you have a protocol with a static method and a class which implements it:
protocol Something {
static func doSomething()
}
class SomethingConcrete: Something {
static func doSomething() {
// does something concrete
}
}
Also there's a generic function. If it gets the type Something
it calls it's static method (there's no object involved).
There's two ways of doing this: overloading and casting.
Overloading (a credit to @portella)
func someFunction<T: Something>() {
T.doSomething()
}
func someFunction<T>() {
// does something else
}
Casting (uses a type check mentioned by @Hiron)
func someFunction<T>() {
if T.self is Something.Type {
(T.self as! Something.Type).doSomething()
} else {
// does something else
}
}
Upvotes: 0
Reputation: 853
Does this fit your needs:
protocol Loggable {
func log()
static func staticLog()
}
func log<L: Loggable>(object: L) {
object.log()
L.staticLog()
}
You ensure that all the objects sent into the function conforms to the protocol Loggable
For me, i don't like this, but hope the following solution can help (i strongly recommend the first one):
protocol Loggable {
func log()
static func staticLog()
}
func log<L>(object: L) {
guard let loggableObject = object as? Loggable else {
print("💩 Not a loggable object")
return
}
loggableObject.log()
type(of: loggableObject).staticLog()
}
final class NotLoggableClass {}
final class LoggableClass: Loggable {
func log() {
print("👏")
}
static func staticLog() {
print("😕")
}
}
log(object: NotLoggableClass())
log(object: LoggableClass())
The call log(object: NotLoggableClass())
will return: 💩 Not a loggable object
The call log(object: LoggableClass())
will return: 👏😕
EDIT: regarding the update, do you want to check the argument type or the argument type? You are not sending any argument into your function, which seems odd. I think you would like to validate it, not the return, i guess. Is this what you are trying to achieve:
protocol Coding {
associatedtype T
static func decodeObject<T>(data: Data) -> T?
}
extension UIImage: Coding {
typealias T = UIImage
static func decodeObject<T>(data: Data) -> T? {
return UIImage(data: data) as? T
}
}
Regarding your solution, i don't understand the objects
or where that came from.
If you want the generic type to conform with the Coding
protocol
you can make that with a constraint in the function declaration.
Example:
protocol Coding {
associatedtype T
static func from(data: Data) -> T?
}
func decodeObject<T: Coding>(_ objects: [Data]) -> T? {
guard let object = objects.first else {
return nil
}
var objects = objects
objects.removeFirst()
return T.from(data: object) as? T
}
extension String: Coding {
static func from(data: Data) -> String? {
return String(data: data, encoding: .utf8)
}
}
Although, i don't understand the objects, this should be something to be done by the type itself, not by a common helper or something, which seems to me what you are trying.
Try to avoid dynamic cast and type with Swift 😉
Hope that helps 🍻
Upvotes: 1
Reputation: 1487
Maybe you should write
if T.self is Coding.Type
instead of
if T.self is Coding
Upvotes: 1