swiftobjective-cgenericsdowncastupcasting

Upcast non-generic ObjC Classes to parent class for Swift method parameter


I have some classes defined in Objective-C similar to this:

@interface Type: NSObject {
    
}
@end

@interface SubType1: Type {
    
}
@end

@interface SubType2: Type {
    
}
@end

@interface Parent <T: __kindof Type *> : NSObject
@property (nonatomic, strong) NSArray <T> *anArray;
@property (nonatomic, strong) T anObject;
@end

@interface SubParent1: Parent<SubType1 *> {
    
}
@end

@interface SubParent2: Parent<SubType2 *> {
    
}
@end

And I am trying to make a Swift function that can take any subclass of Parent. I tried the following:

func callFunc(parent: Parent<Type>) {
                
}
callFunc(parent: SubParent1())

And I get the error: Cannot convert value of type 'Parent<SubType1> to expected argument type 'Parent<Type>'

Also tried:

func callFunc<T>(parent: T) where T: Parent<Type>{

}
callFunc(parent: SubParent1())

And I get the error Type of expression is ambiguous without more context.

In general I want a method that can handle any type of sub-parent class (SubParent1, SubParent2) which has a subtype of the parent class type (SubType1, SubType2) since the method only needs to access properties defined on the Parent. Switching the Objective-C classes is not a possible option due to some other limitations so I am looking for a solution that keeps the classes defined in Objective-C. Not sure if possible but if it is possible can I downcast afterwards if the parameter is expected as the Parent?

Later Edit: Also how can I allow a function to return any sub-parent type in Swift for example:

enum AnEnum {
    case subParent1(_ : SubParent1)
    case subParent2(_ : SubParent2)
    
    func subParent<T: Type>() -> Parent<T>? {
        switch self {
        case .subParent1(let sub1):
            return sub1
        case .subParent2(let sub2):
            return sub2
        }
    }
}

The compiler complains about sub1 and sub2 that 'Type of expression is ambiguous without more context'.


Solution

  • You're parameterizing on Parent rather than Type, which the thing you're actually changing. You mean:

    func callFunc<T>(parent: Parent<T>) { ... }
    

    While you could explicitly call out T: Type, this isn't really necessary, since Parent already enforces that.