Conversion operator in swift
Disclaimer/TL;DR! This answer pertains to the technical question as to whether we can possibly implement implicit bridging mechanisms between different Swift types ourself. The answer is: for some cases, yes, but only in a limited sense and by means of "hacks": do not use this is production code!
Swift internal protocol abuse: we may implement implicit mechanisms to Obj-C objects (e.g. NSNumber
, NSString
...)
As MartinR writes in his comment, custom conversion methods are not present for (native) Swift.
For the technical discussion we can, however, (ab)use the internal protocol _ObjectiveCBridgeable
to allow implicit bridging from your enum to Obj-C objects, in this case e.g. NSString
. For a more detailed Q&A of the subject of the internal protocol _ObjectiveCBridgeable
, see
- Is it possible to replicate Swifts automatic numeric value bridging to Foundation (NSNumber) for (U)Int8/16/32/64 types?
Before proceeding, I'll quote a disclaimer from my answer in thread above:
... note that
_ObjectiveCBridgeable
is an internal/hidden protocol
(_UnderScorePreFixedProtocol
), so solutions based on it might break
without warning in upcoming Swift versions.
Example #1: implementing implicit bridging of your enum to NSString
First lets add a failable initializer to your enum, allowing (attempted) initialization by String
instances:
import Foundation
enum MyEnum: Int {
case Case1 = 0
case Case2
init?(string: String) {
switch string {
case "Case 1": self = .Case1
case "Case 2": self = .Case2
default: return nil
}
}
}
Next up, let MyEnum
conform to _ObjectiveCBridgeable
, as described in more detail in the thread linked to above
extension MyEnum: _ObjectiveCBridgeable {
typealias _ObjectiveCType = NSString
static func _isBridgedToObjectiveC() -> Bool {
return true
}
static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
func _bridgeToObjectiveC() -> _ObjectiveCType {
return NSString(string: "Case \(self.rawValue+1)")
}
static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) {
result = MyEnum(string: source as String)
}
static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool {
self._forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
With the conformance above, we can now make use of implicit bridging from MyEnum
instances to NSString
/* example usage */
var myCase: MyEnum = .Case1
var enumNSstr: NSString = myCase // MyEnum -> NSString, implicit
print(enumNSstr) // Case 1
enumNSstr = "Case 2"
// NSString -> MyEnum, by type conversion (castable)
myCase = (enumNSstr as MyEnum) ?? .Case1
print(myCase) // Case 2
Example #2: implementing implicit bridging of your enum to a custom Swift native type
We may even abuse the _ObjectiveCBridgeable
protocol further, using its (deep backend) mechanisms to implement implicit bridging between two native Swift types, with the limitation that the type bridged to must be a reference type (specifically: instances of the type must be representable by AnyObject
, hence the reference type limitation).
Let MyEnum
be as defined above, but additionally, define a reference (class) type Foo
, and conform MyEnum
to _ObjectiveCBridgeable
with the bridged to type, _ObjectiveCType
being set to Foo
.
class Foo {
var bar: String
init(bar: String) { self.bar = bar }
}
extension MyEnum: _ObjectiveCBridgeable {
typealias _ObjectiveCType = Foo
static func _isBridgedToObjectiveC() -> Bool {
return true
}
static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
func _bridgeToObjectiveC() -> _ObjectiveCType {
return Foo(bar: "Case \(self.rawValue+1)")
}
static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) {
result = MyEnum(string: source.bar)
}
static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool {
self._forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
We can now make use of implicit bridging from MyEnum
instances to Foo
/* example usage */
var myCase: MyEnum = .Case1
var myFoo: Foo = myCase // MyEnum -> Foo, implicit
print(myFoo.bar) // Case 1
myFoo.bar = "Case 2"
// Foo -> MyEnum, by type conversion (castable)
myCase = (myFoo as? MyEnum) ?? .Case1
print(myCase) // Case 2
Finally note that you may, for any given type (say, MyEnum
), naturally only implement implicit bridging to a single other (reference) type; since you can only conform to _ObjectiveCType
once (for a unique type for the typealias _ObjectiveCType
), otherwise yielding a compile time error for redundant protocol conformance.
The above is tested for Swift 2.2.
Can you overload type-casting operators in Swift?
No, the language doesn't provide such functionality for custom types. There is bridging between Objective-C collections and Swift collections but that's baked in and not customizable.
// Swift array of `String` elements
let swiftArray: [String] = ["Bob", "John"]
// Obj-C array of `NSString` elements, but element type information
// is not known to the compiler, so it behaves like an opaque NSArray
let nsArray: NSArray = ["Kate", "Betty"]
// Obj-C array of an `NSString` and an `NSNumber`, element type
// information is not known to the compiler
let heterogeneousNSArray: NSArray = ["World", 3]
// Casting with `as` is enough since we're going from Swift array to NSArray
let castedNSArray: NSArray = swiftArray as NSArray
// Force casting with `as!` is required as element type information
// of Obj-C array can not be known at compile time
let castedSwiftArray: [String] = nsArray as! [String]
// Obj-C arrays can not contain primitive data types and can only
// contain objects, so we can cast with `as` without requiring a
// force-cast with `!` if we want to cast to [AnyObject]
let heterogeneousCastedNSArray: [AnyObject] = heterogeneousNSArray as [AnyObject]
Documentation for type casting is available here.
I think you can achieve what you want to do with initializers.
extension X {
init(string: String) {
self = X(string)
}
}
extension String {
init(x: X) {
// toString is implemented elsewhere
self = x.toString
}
}
let x = X()
let string = "Bobby"
let xFromString: X = X(string: string)
let stringFromX: String = String(x: x)
Not directly related to your question but there is also a family of protocols that start with ExpressibleBy...
, enabling you to do things like the following:
Let's say we want to initialize strings from integer literals. We can do that by conforming to and implementing ExpressibleByIntegerLiteral
// Strings can not be initialized directly from integer literals
let s1: String = 3 // Error: Can not convert value of type 'Int' to specified type 'String'
// Conform to `ExpressibleByIntegerLiteral` and implement it
extension String: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
// String has an initializer that takes an Int, we can use that to
// create a string
self = String(value)
}
}
// No error, s2 is the string "4"
let s2: String = 4
A nice use case for ExpressibleByStringLiteral
can be found here.
Convert String to operator - swift
try something like this
var s = " 1 + 9 X 8"
s = s.replacingOccurrences(of: "X", with: "*")
let expn = NSExpression(format:s)
print("\(expn.expressionValue(with: nil, context: nil) ?? 0)")
How to define an explicit casting operator in swift?
I don't know this is what you want but, you can implement cast like Int
initializer:
extension Int {
init(_ foo:Foo) {
self = foo.i
}
}
let f = Foo()
f.i = 12
let intVal = Int(f) // -> 12
Does Swift support implicit conversion?
There is no implicitly cast in Swift.
Easy way of conversion in swift is using constructor of particular type.
Like if you want to get Float from double then you can use Float(doubleValue)
and Same way if you want to convert float to integer then you can use Int(floatValue)
.
In your case:
let intValue = UInt8(doubleValue)
Beware that you will lose any value after the decimal point. So, choose a better way. Above conversion is just to help you in understanding.
Note that Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers.
Swift simplify optional Int to String conversion with nil coalescing operator
Here's one solution:
let str = "\(num.map { String($0) } ?? "?") foo"
This returns "? foo"
if num
is nil
or it returns "42 foo"
if num
is set to 42
.
Swift-Binary operator cannot be applied to operands, when converting degrees to radians
let degree = arc4random_uniform(360)
let radian = Double(degree) * .pi/180
you need to convert the degree to double before the multiplication .
from apple swift book:
Integer and Floating-Point Conversion
Conversions between integer and floating-point numeric types must be made explicit:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double
Here, the value of the constant three is used to create a new value of type Double, so that both sides of
the addition are of the same type. Without this conversion in place, the addition would not be allowed.
Floating-point to integer conversion must also be made explicit. An integer type can be initialized
with a Double or Float value:
1 let integerPi = Int(pi)
2 // integerPi equals 3, and is inferred to be of type Int
Floating-point values are always truncated when used to initialize a new integer value in this way.
This means that 4.75 becomes 4, and -3.9 becomes -3.
Related Topics
No Designated Init for Skshapenode(Circleofradius: Radius)
Recursion Over a Swift Sliceable
JSONencoder Won't Allow Type Encoded to Primitive Value
Referencing Self in Super.Init
How to "Explicitly" Implement a Protocol in Swift? If It Is Impossible, Why
Sending Firebase Push Notifications to Logged-In Users Only
Changing Texteditor Background Color in Swiftui for MACos
How to Pass/Get Core Data Context in Swiftui Mvvm Viewmodel
Is There *Any* Situation Under Which "For _ in [1,2,3]" Will Not Loop at All
Swift Protocol with Variadic Property
Swift 2: Invalid Conversion from Throwing Function of Type to Non-Throwing Function
Change Width of a Uibarbuttonitem in a Uinavigationbar in Swift
Saving Swifty JSON Array to User Defaults
Images Inaccessible from Asset Catalog in a Swiftui Framework
Capturing a Struct Reference in a Closure Doesn't Allow Mutations to Occur
Retrieving an Array from Firebase