【问题标题】:Swift ambiguous methods with variadic parameter带有可变参数的 Swift 模糊方法
【发布时间】:2016-07-18 12:02:27
【问题描述】:

我有以下方法

static func t(key: String, params: AnyObject...) -> String{
    let string = .......
    if (params.count == 0){
        return string
    } else {
        return String(format: string, params)
    }
}

问题是我需要在 Objective C 中使这个方法可用,这对于可变参数是不可能的。我试图做的是为目标 c 创建另一种方法,其中 params 是一个数组。但是当没有参数时,我还需要第三个。

@objc static func t(key: String, params: [AnyObject]) -> String
@objc static func t(key: String) -> String

但现在 swift 抱怨 t 方法不明确,因为第 1 和第 3 方法只能获取密钥。

如何做到这一点?我知道我可以使用不同的名称,但我希望保持一致。

更新: 另一个问题是我无法在函数内部正确调用String(format:...),因为params 是一个数组而不是一组参数。有什么好办法解决吗?

【问题讨论】:

    标签: objective-c swift variadic-functions variadic


    【解决方案1】:

    您可以执行以下操作:

    @objc(C)
    public class C : NSObject {
    
        public static func t(key: String, params firstParam: AnyObject, _ params: AnyObject...) -> String {
            return t(key, params: [firstParam] + params)
        }
    
        @objc
        public static func t(key: String, params: [AnyObject]) -> String {
            return "TODO"
        }
    
        @objc
        static func t(key: String) -> String {
            return t(key, params: [])
        }
    }
    

    ...从 Swift 调用:

    C.t("")
    C.t("", params: 1)
    C.t("", params: 1, 2)
    C.t("", params: [1, 2, 3])
    

    这是桥接如下:

    SWIFT_CLASS_NAMED("C")
    @interface C : NSObject
    + (NSString * _Nonnull)t:(NSString * _Nonnull)key params:(NSArray * _Nonnull)params;
    + (NSString * _Nonnull)t:(NSString * _Nonnull)key;
    - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
    @end
    

    并且可以发送如下消息:

    #import "DarkSide.h"
    #import "ObjCInterOp-Swift.h"
    
    @implementation DarkSide
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            [C t:@"" params:@[]];
            [C t:@""];
        }
        return self;
    }
    @end
    

    关于问题的更新,有一个格式化的String 初始化程序版本采用[CVarArgType] 而不是CVarArgType...

    func f(format format: String, _ params: [CVarArgType]) -> String {
        return String(format: format, arguments: params)
    }
    
    f(format: "%d %d %d", [1, 2, 3]) // "1 2 3"
    

    只有CVarArgType 不能在Objective C 中表示,这确实使事情变得复杂。事实上,如果你真的必须使用 String.init(format: String, arguments: [CVarArgType]) 并且 从 Objective C 中获取它,那么我目前不知道如何避免从 AnyObjects 转换为 CVarArgTypes以下模糊代码行:

    @objc(C)
    public class C : NSObject {
    
        public static func t(key: String, params: CVarArgType...) -> String {
            return t(key, params: params)
        }
    
        public static func t(key: String, params: [CVarArgType]) -> String {
            return String(format: key, arguments: params)
        }
    
        @objc(t:params:)
        public static func t_objc(key: String, params: [AnyObject]) -> String {
            let args = params.map{
                // here you'll probably need to parse `key` so as to 
                // know what to cast into!
                ($0 as! NSNumber).integerValue as CVarArgType
            }
            return t(key, params: args)
        }
    
        @objc(t:)
        static func t_objc(key: String) -> String {
            return t(key)
        }
    }
    

    我的建议是要么放弃 String.init(format: String, arguments: [CVarArgType]) 之类的东西,要么在 Objective C 中实现基本方法...

    【讨论】:

    • 如问题中所述,当您从 Swift 调用没有附加参数的方法时会出现问题,例如let foo = C.t("bar").
    • 太棒了!希望它更漂亮:),但它有效!
    • 其实我遇到了另一个问题。我更新了我的问题。你能帮忙吗?
    • 嗨,Andrei,每个问题本身都可以完美解决(请参阅更新的答案),但将它们放在一起真是令人头疼!我不确定是否有一个优雅的解决方案,尽管我很想被证明是错误的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-13
    • 2014-07-27
    • 2016-08-11
    • 2016-06-11
    • 2016-05-08
    • 2018-03-20
    • 2013-04-07
    相关资源
    最近更新 更多