简体   繁体   English

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

[英]How do you do java equivalent of Generic callback interface in Swift

In java you can declare an interface like this 在java中,您可以声明这样的接口

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

And you can use this as a type parameter in another method like this 你可以在另一个方法中使用它作为类型参数

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);
}

As you can see I used the interface for callback from some asynchronous task that runs on a different thread. 正如您所看到的,我使用接口从一个在不同线程上运行的异步任务进行回调。

UPDATE UPDATE

Following this guide , I have come up with a solution similar to this 按照本指南 ,我提出了类似的解决方案

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)
    }
}

Now in my doSomeAsyncTask method I can just pass GenericProtocolThunk<MyObject> as the parameter type. 现在在我的doSomeAsyncTask方法中,我可以将GenericProtocolThunk<MyObject>作为参数类型传递。 Is this the right way to achieve what I asked in the question? 这是实现我在问题中提出的问题的正确方法吗? Honestly it looks quite ugly to me. 老实说,对我来说这看起来很难看。

I think your problem boils indeed down to what is also noted in the blog post you link to: 我认为您的问题确实归结为您链接到的博客文章中也提到的内容:

"Protocols in Swift can be generic via abstract type members rather than parameterisation. Consequently, the protocol itself can no longer be used as a type but only as a generic constraint." “Swift中的协议可以通过抽象类型成员而不是参数化来实现。因此,协议本身不能再用作类型,而只能用作通用约束。”

The (ugly) thunk based workaround looks like it solves your problem indeed, although to verify it would help if in your question you used similar terminology for both your Java and Swift examples, and they would be complete, including the type that actually contains the doSomeAsyncTask method to avoid possible confusions. (丑陋的)基于thunk的解决方案看起来确实解决了你的问题,尽管如果在你的问题中你使用类似的Java和Swift示例的术语来验证它会有所帮助,并且它们将是完整的,包括实际包含的类型doSomeAsyncTask方法可以避免可能的混淆。

I can think of a few alternative more Swift friendly solutions if you can change the formulation a bit. 如果你能稍微改变配方,我可以想到一些替代Swift友好的解决方案。

If you could describe Result too with a protocol, then the language isn't fighting against you quite so much. 如果你也可以用协议来描述结果,那么语言就不会对你起作用了。 Compared to Java, conforming to a protocol (= implementing an interface) is also not limited to just class types, as shown in the below example so arguably you get a bit more rather out of the language to this end, than in Java: 与Java相比,符合协议(=实现接口)也不仅限于类类型,如下面的示例所示,因此可以说,为了达到这个目的,您可以比Java更多地使用语言:

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)
        }
    }
}

Another alternative that I've used only recently myself in a related sort of problem is to model result as an enum which enumerates the possible result types, like below (incidentally, each of BibliographyItem , InlineMathFragment , Equation , BlockElement , InlineElement in my code example below are themselves protocols, not concrete types): 我最近才在相关类型的问题中使用的另一种替代方法是将结果建模为枚举,枚举可能的结果类型,如下所示(顺便InlineElement ,我的代码示例中的每个BibliographyItemInlineMathFragmentEquationBlockElementInlineElement下面是协议,而不是具体类型):

public enum Result {
    case None
    case BibliographyItems([BibliographyItem])
    case InlineMathFragments([InlineMathFragment])
    case Equations([Equation])
    case BlockElements([BlockElement])
    case InlineElements([InlineElement])
}

This is handy in a situation where your results come from some already known set of result types, and you commonly end up needing to deal with them in some conditional form. 在您的结果来自一些已知的结果类型集合的情况下,这很方便,并且您通常最终需要以某种条件形式处理它们。

You may want to simplify it to: 您可能希望将其简化为:

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

Check out this great video: 看看这个精彩的视频:

Rob Napier: Beyond Crusty: Real world protocols Rob Napier:超越硬壳:真实世界的协议

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM