Protocols
A protocol that is conformed to by an object is not truly used unless it’s also used as an existential type or to specialize a generic method/class. Periphery is able to identify such redundant protocols whether they are conformed to by one or even multiple objects.
protocol MyProtocol { // 'MyProtocol' is redundant func someMethod()}
class MyClass1: MyProtocol { // 'MyProtocol' conformance is redundant func someMethod() { print("Hello from MyClass1!") }}
class MyClass2: MyProtocol { // 'MyProtocol' conformance is redundant func someMethod() { print("Hello from MyClass2!") }}
let myClass1 = MyClass1()myClass1.someMethod()
let myClass2 = MyClass2()myClass2.someMethod()Here we can see that despite both implementations of someMethod being called, at no point does an object take on the type of MyProtocol. Therefore, the protocol itself is redundant, and there’s no benefit from MyClass1 or MyClass2 conforming to it. We can remove MyProtocol along with each redundant conformance and just keep someMethod in each class.
Just like a normal method or property of an object, individual properties and methods declared by your protocol can also be identified as unused.
protocol MyProtocol { var usedProperty: String { get } var unusedProperty: String { get } // 'unusedProperty' is unused}
class MyConformingClass: MyProtocol { var usedProperty: String = "used" var unusedProperty: String = "unused" // 'unusedProperty' is unused}
class MyClass { let conformingClass: MyProtocol
init() { conformingClass = MyConformingClass() }
func perform() { print(conformingClass.usedProperty) }}
let myClass = MyClass()myClass.perform()Here we can see that MyProtocol is itself used and cannot be removed. However, since unusedProperty is never called on MyConformingClass, Periphery can identify that the declaration of unusedProperty in MyProtocol is also unused and can be removed along with the unused implementation of unusedProperty.