I am using the public method as below to convert the API data type into Int.
public func convertToInt( value : Any) -> Int{
if let v = value as? Strin
The problem is both that global Swift functions are unavailable to Objective-C, and the protocol Any
cannot be represented in Objective-C.
Therefore, one potential solution is to encapsulate your function in a helper class, and to use AnyObject
for your value
argument – as Int
and String
can be freely bridged to NSNumber
and NSString
respectively, and thus can be treated as objects when Foundation is imported.
@objc final class HelperFunctions : NSObject {
static func convertToInt(value : AnyObject) -> Int {
if let v = value as? String {
if let myNumber = NSNumberFormatter().numberFromString(v) {
return myNumber.integerValue
} else {
print ("Cannot convert to Int...")
}
} else if let v = value as? Int {
print("int")
return v
}
// note that this check is completely redundant as NSNumber is freely bridgable
// to Int – therefore the 'as? Int' check will always get triggered instead
else if let v = value as? NSNumber {
print("nsnum")
return v.integerValue
}
return 0
}
}
Although that being said, this really isn't very Swifty code. NSNumber
is bridgeable to Int
, so you can already convert it directly:
let n = NSNumber(integer: 5)
let i = n as Int // 5
And Int
already has an initialiser that can take a string:
let i = Int("55") // Optional(55)
So, I don't really see what Swift problem this function is solving. Although I do see the Objective-C problem that it's solving, and for that reason I would simply implement this function as a C function in an Objective-C file.
extern NSInteger convertToInt(id _Nonnull value);
inline NSInteger convertToInt(id _Nonnull value) {
if ([value isKindOfClass:[NSString class]]) {
NSNumberFormatter* f = [[NSNumberFormatter alloc] init];
return [f numberFromString:(NSString*)value].integerValue;
} else if ([value isKindOfClass:[NSNumber class]]) {
return ((NSNumber*)value).integerValue;
}
return 0;
}
You can always import this back into Swift if you really want – and then it'll be available as a global function. But I would recommend that you don't import this back to Swift, and instead find a more Swifty solution to your problem.
For example, I would recommend that you implement this in Swift using protocols and extensions. You can define an IntRepresentable
protocol in order to represent types that can be converted to Int
. The advantage of doing this is that you're being explicit about the types that you can convert to Int
, rather than letting it be an implementation detail of your convenience function.
protocol IntRepresentable {
func _asInt() -> Int?
}
Now you can extend the types that your dictionary could contain and make them conform to IntRepresentable
.
extension NSString : IntRepresentable {
func _asInt() -> Int? {return Int(self as String)}
}
extension NSNumber : IntRepresentable {
func _asInt() -> Int? {return self.integerValue}
}
// not really necessary, as your dict will be [Whatever:AnyObject],
// so the NSString extension will be used – here for completeness
extension String : IntRepresentable {
func _asInt() -> Int? {return Int(self)}
}
extension Int : IntRepresentable {
func _asInt() -> Int? {return self}
init?(representable:IntRepresentable) {
guard let i = representable._asInt() else {return nil}
self = i
}
}
Now you can convert your dictionary from [Whatever:AnyObject]
to [Whatever:Int]
by doing the following:
let inputDict = ["foo":"5", "bar":6, "baz":NSNumber(int:5)]
var outputDict = [String:Int]()
for (key, value) in inputDict {
if let value = value as? IntRepresentable {
outputDict[key] = Int(representable: value)
}
}
print(outputDict) // ["baz": 5, "foo": 5, "bar": 6]
You can always stick this in a convenience function if it makes you feel better, although I would still advocate against global functions. You can use a caseless enum in order to avoid polluting the global namespace:
enum DictionaryConversion {
static func toIntValues<Key>(dict:[Key:NSObject]) -> [Key:Int] {
var outputDict = [Key:Int]()
for (key, value) in dict {
if let value = value as? IntRepresentable {
outputDict[key] = Int(representable: value)
}
}
return outputDict
}
}
Or just extend Dictionary
itself:
extension Dictionary {
func convertValuesToInt() -> [Key:Int] {
var outputDict = [Key:Int]()
for (key, value) in self {
if let value = value as? IntRepresentable {
outputDict[key] = Int(representable: value)
}
}
return outputDict
}
}
let outputDict = DictionaryConversion.toIntValues(inputDict)
let outputDict = inputDict.convertValuesToInt()
Setup your project to use both swift and objective c. Here is the link for that Then you need to import the Swift class in the similar way you import Objective C class and use it in the same way you would have used in Objective C Class.