簡體   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