在Swift中函数调用失败

时间:2014-09-07 07:04:33

标签: generics swift downcast

我有一个字典,其中包含函数调用以及用于向该字典添加函数的通用方法。我转发该泛型函数以便将其添加到字典中的那一刻,编译器崩溃了。

当您将以下代码放在游乐场时,您可以看到:

import Cocoa

class Email:NSObject {
    var Subject:String = ""
}
class SMS:NSObject {
    var Message:String = ""
}

var allfunc = Dictionary<String, (item: NSObject) -> Void>()

func test<T:NSObject>(type:T, myfunc:(item: T) -> Void) {
    allfunc[NSStringFromClass(type.dynamicType)] = myfunc as? (item:NSObject) -> Void
}

test(Email(), {item in NSLog("\(item.Subject)")})
test(SMS(), {item in NSLog("\(item.Message)")})

for (key: String, value: (item: NSObject) -> Void) in allfunc {
    if key == NSStringFromClass(Email().dynamicType) {
        var mail = Email()
        mail.Subject = "testing mail"
        value(item: mail)
    } else {
        var sms = SMS()
        sms.Message = "testing SMS"
        value(item: sms)
    }
}

当我将测试功能更改为此时,我不会崩溃,但我将失去自动完成功能:

func test<T:NSObject>(type:T, myfunc:(item: NSObject) -> Void) {
    allfunc[NSStringFromClass(type.dynamicType)] = myfunc
}

这是一个编译器错误,你不能低估功能,或者不应该是可能的吗? 有没有可以用来创建类似功能的替代方案?

也许操场上的代码看起来有点奇怪。它是我项目的修改后的摘录。如果您想查看具有相同崩溃的完整项目,请查看https://github.com/evermeer/EVCloudKitDao

1 个答案:

答案 0 :(得分:0)

你不能施放功能。在当前的Xcode版本6.2中,您将获得以下运行时异常:Swift动态转换失败

然而,我在https://github.com/evermeer/EVCloudKitDao的连接函数中实现了这个问题的解决方法。解决方案是包装函数而不是强制转换它。代码如下所示:

public var insertedHandlers = Dictionary<String, (item: EVCloudKitDataObject) -> Void>()
public var updateHandlers = Dictionary<String, (item: EVCloudKitDataObject, dataIndex:Int) -> Void>()

public func connect<T:EVCloudKitDataObject>(
    type:T,
    completionHandler: (results: [T]) -> Void,
    insertedHandler:(item: T) -> Void,
    updatedHandler:(item: T, dataIndex:Int) -> Void,
    deletedHandler:(recordId: String, dataIndex:Int) -> Void,
    errorHandler:(error: NSError) -> Void
    ) -> Void {
        func insertedHandlerWrapper(item:EVCloudKitDataObject) -> Void {
            insertedHandler(item: item as T)
        }
        func updatedHandlerWrapper(item:EVCloudKitDataObject, dataIndex:Int) -> Void {
            updatedHandler(item: item as T, dataIndex: dataIndex)
        }
        self.insertedHandlers[filterId] = insertedHandlerWrapper
        self.updateHandlers[filterId] = updatedHandlerWrapper
        ...

现在updateHandler仍然使用T而不是EVCloudKitDataObject,并且在处理程序本身中你可以使用原始类型而不需要强制转换它。