你如何在Swift中使用Java等效的Generic回调接口

时间:2016-04-29 11:41:07

标签: swift swift-protocols

在java中,你可以声明一个像这样的接口

public interface Foo<T>
{
    public void doFoo(T result);
}

你可以在另一个方法中使用它作为类型参数,比如

public void doSomeAsyncTask(final Foo<MyObject> foo)
{
    Runnable asyncRunnable = new Runnable()
    {
        @Override
        void run()
        {
            MyObject result;
            // do task to get result
            foo.doFoo(result);
        }
    };
    Thread asyncThread = new Thread(asyncRunnable);
    asyncThread.start();
}

foo.doFoo(result);
}

正如您所看到的,我使用接口从一个在不同线程上运行的异步任务进行回调。

更新

this guide之后,我提出了类似于此

的解决方案
public protocol GenericProtocol {
    associatedType T
    func magic(result:T)
}

class GenericProtocolThunk<T> : GenericProtocol {
    private let _magic : (T)

    init<P : GenericProtocol where P.T == T>(_dep : P) {
        _magic = p.magic
    }

    func magic(result: T) {
        _magic(result)
    }
}

现在,在我的doSomeAsyncTask方法中,我可以将GenericProtocolThunk<MyObject>作为参数类型传递。这是实现我在问题中提出的问题的正确方法吗?老实说,我看起来很难看。

2 个答案:

答案 0 :(得分:2)

我认为您的问题确实归结为您链接到的博客文章中所指出的内容:

  

“Swift中的协议可以通过抽象类型成员通用   比参数化。因此,协议本身不再   用作类型但仅作为通用约束。“

(丑陋的)基于thunk的解决方案看起来确实解决了你的问题,虽然如果在你的问题中你为Java和Swift示例使用类似的术语来验证它会有所帮助,并且它们将是完整的,包括类型实际上包含doSomeAsyncTask方法以避免可能的混淆。

如果您可以稍微更改配方,我可以考虑一些替代Swift友好的解决方案。

如果你能用协议来描述结果,那么这种语言就不会对你起作用了。与Java相比,符合协议(=实现接口)也不仅仅限于类类型,如下面的示例所示,因此可以说,为了达到这个目的,您可以比Java更多地使用语言:< / p>

import Foundation

protocol Result {
    // any restrictions on Result that you need.
}

class A:Result { }
struct B:Result { }
enum C:Result { case X }

protocol Foo {
    func doFoo(result:Result) -> Void
}

class Bar {
    func doSomeAsyncTask(foo:Foo) -> Void {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
            foo.doFoo(A())
            foo.doFoo(B())
            foo.doFoo(C.X)
        }
    }
}

我最近在相关类型的问题中使用的另一种替代方法是将结果建模为枚举,枚举可能的结果类型,如下所示(顺便提一下,每个BibliographyItem,{{1}我的代码示例中的{},InlineMathFragmentEquationBlockElement本身就是协议,而不是具体的类型):

 
InlineElement

这种情况很方便,你的结果来自一些已知的结果类型,你通常最终需要以某种条件形式处理它们。

答案 1 :(得分:1)

您可能希望将其简化为:

func doSomeAsyncTask<T>(callback: (T)->Void)

看看这个精彩视频:

Rob Napier: Beyond Crusty: Real world protocols