How to List All Classes Conforming to Protocol in Swift

How to list all classes conforming to protocol in Swift?

Since you're using the Objective-C runtime to get the type introspection you need to add @objc to your code in this manner:

@objc protocol Animal {
func speak()
}

class Cat:Animal {
@objc func speak() {
print("meow")
}
}

class Dog: Animal {
@objc func speak() {
print("Av Av!")
}
}

class Horse: Animal {
@objc func speak() {
print("Hurrrr")
}
}

Note that this kind of type introspection might be very slow.

In Swift, can you find all types in a module that adhere to a specific protocol?

I don't believe Swift currently has a 'native' (not dependant on the Objective-C runtime) API for doing this kind of reflection.

However, if you're on an Apple platform (and therefore have Obj-C interoperability), you could get a list of all classes registered with the Obj-C runtime, and then filter those that conform to a given protocol. This will work for Swift classes (even those that don't inherit from NSObject) because under the hood Swift classes are built on top of Obj-C classes (when there's Obj-C interop).

Because this will only work for classes (not structures or enumerations), you may want to restrict your protocol such that only classes can conform to it:

protocol Favorite : class {}

You can then do the following, using objc_copyClassList:

import Foundation

protocol Animal {}
protocol Vehicle {}
protocol Favorite : class {}

class Dog : Animal {}
class Cat : Animal, Favorite {}
class Car : Vehicle {}
class Bicycle : Vehicle, Favorite {}

/// Invokes a given closure with a buffer containing all metaclasses known to the Obj-C
/// runtime. The buffer is only valid for the duration of the closure call.
func withAllClasses<R>(
_ body: (UnsafeBufferPointer<AnyClass>) throws -> R
) rethrows -> R {

var count: UInt32 = 0
let classListPtr = objc_copyClassList(&count)
defer {
free(UnsafeMutableRawPointer(classListPtr))
}
let classListBuffer = UnsafeBufferPointer(
start: classListPtr, count: Int(count)
)

return try body(classListBuffer)
}
// .flatMap in Swift < 4.1
let classes = withAllClasses { $0.compactMap { $0 as? Favorite.Type } }
print(classes) // [Bicycle, Cat]

Here we're calling compactMap(_:) on the UnsafeBufferPointer to get back an array of metatypes that represent types conforming to Favorite (i.e those that can be cast to the existential metatype Favorite.Type).

How do I determine what protocols a class conforms to in swift?

I don't believe you can do it without leaning on the Objective-C runtime. Import ObjectiveC and use the class_copyProtocolList() function.

Find out the name of all the implementers of swift protocol

so this is how I did it:

static func getClassesImplementingProtocol(_ protocolName: Protocol!) -> [AnyClass] {

var result = [AnyClass]();

let count: Int32 = objc_getClassList(nil, 0)

guard count > 0 else {
return result
}

let classes = UnsafeMutablePointer<AnyClass>.allocate(
capacity: Int(count)
)

defer {
classes.deallocate()
}

let buffer = AutoreleasingUnsafeMutablePointer<AnyClass>(classes)

for i in 0..<Int(objc_getClassList(buffer, count)) {
let someclass: AnyClass = classes[i]

if class_conformsToProtocol(someclass, protocolName) {

result.append(someclass);
}
}

return result
}

Thanks to : How to list all classes conforming to protocol in Swift?

Return a class that conforms to a swift protocol (the actual class, not an instance of it)

You need to change the type of protConformer to the meta type of the protocol, namely MyProt.Type if you want to return a type conforming to the protocol and not an instance of such a type.

var protConformer: MyProt.Type {
return boolVar ? ClassOne.self : ClassTwo.self
}

How do I get list of all classes conform to certain protocol in Xcode 4?

Use the Objective-C runtime functions.

  • objc_getClassList to get the list of Classes
  • class_getSuperclass or the -superclass method to walk the superclass chain
  • class_conformsToProtocol or the -conformsToProtocol: method to check if a class conforms to a protocol

Return Class conform to protocol

The problem is that for build() you are trying to return a type of Brand, but Hashable has Self requirements as part of its definition. This is why you get the error about "Self or associated type requirements".

A possible solution is to make Brand not Hashable itself, but any class which conforms to Brand and Hashable will get the Hashable implementation for Brand:

protocol Brand: AnyObject {
var name: String { get }
}

extension Brand where Self: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(name)
}

static func == (lhs: Self, rhs: Self) -> Bool {
lhs.name == rhs.name
}
}

However, accessing build() will not give you a hashValue, since only classes which conform to Brand and Hashable have hashValue.

To fix this, conform Jbl and Columbo to the Hashable protocol. Then add a function like this in the Builder class for example:

func getHashValue() -> Int {
if .random() {
return Jbl().hashValue
} else {
return Columbo().hashValue
}
}

Called like:

print(builder.getHashValue())
// Prints: -8479619369585612153

Obviously this hash changes each time the app is relaunched, so don't rely on it for persisting data.

And just for style reasons: you may prefer to use the following and make the classes just conform to HashableBrand:

typealias HashableBrand = Brand & Hashable

iOS11 Swift 4 - how to check if Swift class conforms to protocol defined in Objective-C?

[MyClass conformsToProtocol:@protocol(MyProtocol)];

According to Apple Docs you can use conformsToProtocol:which returns a Boolean value that indicates whether the receiver conforms to a given protocol.


Example

@protocol MyProtocol
- (void)helloWorld;
@end

@interface MyClass : NSObject <MyProtocol>
@end

Will be exposed as:

console.log(MyClass.conformsToProtocol(MyProtocol)); 

var instance = MyClass.alloc().init();
console.log(instance.conformsToProtocol(MyProtocol))


Related Topics



Leave a reply



Submit