繁体   English   中英

在Swift中将协议类型作为参数传递

[英]Passing Protocol Type as parameter in Swift

在objective-C中,我们可以(通过导入语言的运行时头文件)执行以下操作:

//Pass a service (usually an object) and ANY protocol
- (void)registerService:(id)service forProtocol:(Protocol *)protocol
{
    //Grab the protocol's name (that's why we import runtime.h, it contains the protocol_getname mehod)
    NSString *protocolName = [NSString stringWithUTF8String:protocol_getName(protocol)];

    //If the object we passed does not conform to the protocol, inform and break
    if (![service conformsToProtocol:protocol])
    {
        NSLog(@"Service: %@ does not conform to protocol: %@", service, protocolName);
        return;
    }

    //Else add service in a collection (array, dictionary) for later use
    self.services[protocolName] = service;
}

我在obj-C中使用它作为“穷人的IOC容器”,一个用于注入依赖项的简单注册表。

//The interested party uses this method to obtain the dependency it needs by asking for the object that is registered as responsible for conforming to the Protocol parameter
- (id)serviceForProtocol:(Protocol *)protocol
{
    id result;

    NSString *protocolName = [NSString stringWithUTF8String:protocol_getName(protocol)];

    //Look for the service that conforms to the protocol in the registry dictionary,
    result = self.services[protocolName];

    //if there is no object meeting the criteria, inform/alert
    if (result == nil)
    {
        NSLog(@"No class registered for protocol: %@", protocolName);
    }

    //and return the result
    return result;
}

试图在Swift中复制这种行为,我发现我们无法像在obj-C中那样访问该语言的等效“运行时”API,并且可以理解,因为swift是一项正在进行的工作并且给予了人们这种访问无疑具有风险。

但这也意味着我们不能再以相同的方式使用协议,即在任何协议的意义上。

我想到的第一个可能的解决方法是混合使用泛型Anywhere ,但对于过去简单的东西来说,感觉太多了。

所以,我的问题是:在Swift中传递协议 (如在任何协议中 )的一些提议解决方案是什么?

编辑:我使用Swift中引入的元类型类型取得了一些成功,这在语言设计方面是有意义的,但也没有提供能够提供元数据类型的“字符串”表示的能力,该元数据类型可用作字典。

这当然是随着语言的成熟而添加的功能。

你有什么尝试?

这样的事情不起作用:

import Foundation

func registerService(service: NSObjectProtocol, forProtocol prot: Protocol) {
  let protocolName = NSStringFromProtocol(prot)

  if (!service.conformsToProtocol(prot)) {
    println("Service: \(service) does not conform to protocol: \(protocolName)")
    return
  }

  //...
}

我尝试了很长时间,有许多不同的方法(指针, Protocol ),并且我发现没有@objc和纯Swift的唯一解决方案是关闭。 然后,您需要使用闭包来使用协议并返回一个值

protocol Proto { }
protocol Proto2 { }
class Foo: Proto { }
class Bar: Proto, Proto2 { }
class Baz: Proto2 { }
class Qux { }

func printConforms(classList: [AnyClass], protoCond: (AnyClass) -> Any?) {
    for i in classList {
        print(i, terminator: " -> ")
        if protoCond(i) != nil {
            print("is subscriber")
        } else {
            print("NOT IS subscriber")
        }
    }
}

let myClasses: [AnyClass] = [Foo.self, Bar.self, Baz.self, Qux.self]
printConforms(classList: myClasses, protoCond: { $0 as? Proto.Type })

更完整的例子: https//gist.github.com/brunomacabeusbr/eea343bb9119b96eed3393e41dcda0c9

编辑

另一个更好的解决方案是使用泛型,例如:

protocol Proto { }
class Foo: Proto { }
class Bar: Proto { }
class Baz { }

func filter<T>(classes: [AnyClass], byConformanceTo: T.Type) -> [AnyClass] {
    return classes.filter { $0 is T }
}

filter(classes: [Foo.self, Bar.self, Baz.self], byConformanceTo: Proto.Type.self)
// return [Foo.self, Bar.self]

暂无
暂无

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

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