I have the following method
static func t(key: String, params: AnyObject...) -> String{
let string = .......
if (params.count == 0){
return string
} else {
return String(format: string, params)
}
}
The problem is that i need to make this method available in Objective C which is impossible with variadic params. What I tried to do is create another method for objective c where params is an array. But then I also need to have third one for when there is no params.
@objc static func t(key: String, params: [AnyObject]) -> String
@objc static func t(key: String) -> String
But now swift complains that method t
is ambiguous because 1st and 3rd method can take just the key.
How to make this work? I know I could use different names, but I would like to keep things consistent.
UPDATE:
Another problem is that I can't call String(format:...)
correctly once inside the function since params is an array and not a group of params. Any nice way to solve this?
You can do the following:
@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: [])
}
}
... calling from Swift:
C.t("")
C.t("", params: 1)
C.t("", params: 1, 2)
C.t("", params: [1, 2, 3])
This is bridged as follows:
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
And can be messaged as follows:
#import "DarkSide.h"
#import "ObjCInterOp-Swift.h"
@implementation DarkSide
- (instancetype)init
{
self = [super init];
if (self) {
[C t:@"" params:@[]];
[C t:@""];
}
return self;
}
@end
Regarding the update to the question, there is a version of the formatted String
initialiser that takes [CVarArgType]
rather than 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"
Only CVarArgType
cannot be represented in Objective C, which really complicates things. In fact, if you really must use String.init(format: String, arguments: [CVarArgType])
and get to it from Objective C then I don't see at the moment how to avoid casting from AnyObject
s to CVarArgType
s along the lines of the following murky code:
@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)
}
}
My suggestion is to either wean off things like String.init(format: String, arguments: [CVarArgType])
, or to implement the base method in Objective C...