将非通用 ObjC 类向上转换为 Swift 方法参数的父类

问题描述

我在 Objective-C 中定义了一些与此类似的类:

@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

我正在尝试创建一个 Swift 函数,它可以采用 Parent 的任何子类。我尝试了以下方法

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

我收到错误Cannot convert value of type 'Parent<SubType1> to expected argument type 'Parent<Type>'

也试过了:

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

}
callFunc(parent: SubParent1())

我收到错误 Type of expression is ambiguous without more context

一般来说,我想要一种可以处理任何类型的子父类 (SubParent1,SubParent2) 的方法,它具有父类类型 (SubType1,{{ 1}}),因为该方法只需要访问在 SubType2 上定义的属性。由于其他一些限制,无法切换 Parent 类,因此我正在寻找一种解决方案,以保留 Objective-C 中定义的类。不确定是否可能,但如果可能的话,如果参数预期为 Objective-C,我之后是否可以向下转型?

稍后编辑:另外,我如何允许函数返回 Swift 中的任何子父类型,例如:

Parent

编译器抱怨 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 } } } sub1 '表达式类型不明确,没有更多上下文'。

解决方法

您在 Parent 而不是 Type 上进行参数化,您实际上正在更改它。你的意思是:

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

虽然您可以明确调用 T: Type,但这并不是真正必要的,因为 Parent 已经强制执行了。

,

这里的问题是您期望协方差,但 Swift 泛型通常不支持协方差。

关于协方差的解释网上有很多,这里就不解释了。但是我将确切地展示协方差如何与您的示例类型不符。考虑以下代码:

let sp1 = SubParent1()
let p = sp1 as Parent<Type>  // (1) Swift forbids this cast...
let t: Type = SubType2()
p.anObject = t               // (2) ...because this assigment would be unsound.

假设 Swift 允许了被禁止的类型转换 (1)。然后赋值 (2) 会将 SubType2 分配给只能包含 SubType1 的属性。

您可以通过使 callFunc 函数在 Parent 子类型和 Type 子类型上通用来解决此问题:

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

编辑:Rob Napier 的回答正确地表明您只需要在 T 上通用,而不是在 P 上。