将非泛型ObjC类向上转换为Swift方法参数的父类
我在将非泛型ObjC类向上转换为Swift方法参数的父类,swift,objective-c,generics,downcast,upcasting,Swift,Objective C,Generics,Downcast,Upcasting,我在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>
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
我得到一个错误:无法将“Parent”类型的值转换为预期的参数类型“Parent”
还尝试:
func callFunc<T>(parent: T) where T: Parent<Type>{
}
callFunc(parent: SubParent1())
编译器抱怨
sub1
和sub2
表示“表达式类型在没有更多上下文的情况下是不明确的”。这里的问题是您期望协方差,但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.
编辑:Rob Napier的回答正确地表明,您只需要在
T
上使用泛型,而不需要在p
上使用泛型。这里的问题是您期望协方差,但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.
编辑:Rob Napier的回答正确地表明,您只需要在
T
上进行泛型,而不需要在p
上进行参数化,而不是在Parent
上进行参数化,而不是在Type
上进行参数化。你的意思是:
func callFunc<T>(parent: Parent<T>) { ... }
func callFunc(父:父){…}
虽然您可以显式地调用
T:Type
,但这并不是必需的,因为Parent已经强制执行了。您正在对Parent
进行参数化,而不是Type
,实际上您正在更改它。你的意思是:
func callFunc<T>(parent: Parent<T>) { ... }
func callFunc(父:父){…}
虽然您可以显式地调用
T:Type
,但这并不是真正必要的,因为父级已经强制执行了该操作。只是一个观察-在Objective-C中,您将在最高、最抽象的级别上工作,它最终将实现最深入的调用,即使这破坏了系统。在Swift的安全环境中,您必须在尽可能最低、最具体的级别上工作,Swift将呼叫尽可能浅的人员以保持安全。感谢您提供的解决方案。你能帮我做“以后编辑”部分吗?编辑应该是一个新问题,但答案是在一般情况下是不可能的。仅使用编译时已知的信息,subParent()的精确返回类型是什么?在这种情况下,这甚至是不可能的,因为我可以通过任何类型的考试。我可以将CBPeripheral
与程序中的Type
一致,并且您必须返回一个Parent
。你会怎么做?您可能需要的是协议或类型擦除器,但这取决于实际使用情况。您应该打开一个问题来解释调用代码的样子。@skaak我不太确定您在这里的意思。在ObjC和Swift中,传递特异性很高或很低的变量是很常见的。Swift往往比ObjC有更多的抽象代码。考虑编写代码,如非常抽象的协议,比如集合和Objc中所做的事情。如果我不举这个例子,很难继续讨论,但我的(具体的,不是一般的)结论是Swift迫使你尽可能具体地工作(保持安全?),即使这样,它也会在安全方面出错。哦,好吧,也许我会把这个例子作为一个问题发布出来,或者如果你真的想继续这一过程,也许我可以在聊天中向你展示它——仅仅是一个观察——在Objective-C中,你会在最高、最抽象的层次上工作,它最终会做出可能的最深刻的呼吁,即使这破坏了系统。在Swift的安全环境中,您必须在尽可能最低、最具体的级别上工作,Swift将呼叫尽可能浅的人员以保持安全。感谢您提供的解决方案。你能帮我做“以后编辑”部分吗?编辑应该是一个新问题,但答案是在一般情况下是不可能的。仅使用编译时已知的信息,subParent()的精确返回类型是什么?在这种情况下,这甚至是不可能的,因为我可以通过任何类型的考试。我可以将CBPeripheral
与程序中的Type
一致,并且您必须返回一个Parent
。你会怎么做?您可能需要的是协议或类型擦除器,但这取决于实际使用情况。您应该打开一个问题来解释调用代码的样子。@skaak我不太确定您在这里的意思。在ObjC和Swift中,传递特异性很高或很低的变量是很常见的。Swift往往比ObjC有更多的抽象代码。考虑编写代码,如非常抽象的协议,比如集合和Objc中所做的事情。如果我不举这个例子,很难继续讨论,但我的(具体的,不是一般的)结论是Swift迫使你尽可能具体地工作(保持安全?),即使这样,它也会在安全方面出错。哦,好吧,也许我会把这个例子作为一个问题发布,或者如果你真的想继续下去,我可以在聊天中展示给你。谢谢你的解决方案。你能帮我处理“以后编辑”部分吗?谢谢你的解决方案。你能帮我做“以后编辑”部分吗?
func callFunc<T>(parent: Parent<T>) { ... }