A protocol can be conformed to by several entities (in your case, class SubClass
), but the protocol itself doesn't know about which entities that are conforming to it. Since your createFactory()
method returns a type (protocol) IInterface
, not type SubClass
, the return as is will not know about members specific to SubClass
, even if a SubClass
object is sent as return.
let mgr = Factory.createFactory() /* Type: let mgr: IInterface */
This is also apparent when attempting to call a member SubClassMethod
(or any unknown member, say .foo
, for that metter) on instance mgr
error: value of type 'IInterface' has no member 'SubClassMethod'
To wrap it up, a type conforming to a protocol will have access to all blueprinted methods and properties in that protocol, but an instance of a protocol used as a type (which is acceptable if you don't have Self or any associated types in your protocol) will know nothing about the methods and properties of other types that happens to conforms to that protocol.
As mentioned below, if you know the return of type IInterface
is of a certain type, then you can attempt a type conversion (as?
) to this type, e.g. ... as? SubClass
. Note however again that the protocol IInterface
doesn't know about which types that conforms to it, to this type conversion can't be asserted as successful in compile time; this is strictly something to be controlled by you as developer, possibly leading to runtime exceptions if you're not careful (e.g. using un-safe methods such as forced conversion as!
). Now, if the function always returns a SubClass
type, you might as well change its signature to
class func createFactory() -> SubClass {
As possible use case of keeping the IInterface
return is if createFactory()
actually do return different types that all conform to the IInterface
protocol. In that case, you could safely use a switch
block over the createFactory()
return to perform type conversion to you different known types (known by developer) that conform to IInterface
, as follows
protocol IInterface {
func InterfaceMethod() -> Void
}
public class SubClass: IInterface {
init() {}
func InterfaceMethod() { }
public func SubClassMethod() { }
}
public class AnotherClass: IInterface {
init() {}
func InterfaceMethod() { }
public func AnotherClassMethod() { }
}
public class Factory {
class func createFactory() -> IInterface {
if arc4random_uniform(5) > 2 {
return SubClass()
}
else {
return AnotherClass()
}
}
}
switch
block over return when calling you factory method:
switch(Factory.createFactory()) {
case let mgr as SubClass:
print("Subclass")
mgr.SubClassMethod()
case let mgr as AnotherClass:
print("AnotherClass")
mgr.AnotherClassMethod()
// default case
case let mgr as IInterface:
print("Unknown specific regarding return type")
}
Finally, possibly the answer to the following SO question can be of value for you