Type conversion when using protocol in Swift
Code Different's answer is right, but it's also important to understand why you can't just reinterpret the data without something doing an O(n) conversion to walk though and wrap each element in a box.
[A]
is an array with elements the size of A
. So, more or less, A[1]
is at memory location A[0] + sizeof(A)
(this isn't exactly true, but pretend it is; it'll make things simpler).
[Test]
has to be able to hold anything that conforms to the protocol. It might be the size of A
, it might be the size of B
, which is larger. To achieve that, it creates a box that holds "something that conforms to Test
". The box is of a known size, and it may have to heap-allocate the thing it points to (or maybe not; depends), but it ain't going to be the same size as both A
and B
, so the layout of [Test]
in memory has to be different than the layout of [A]
or [B]
.
Now as [Test]
could do that O(n) walk for you and force a copy right then. Or it delay the copy until the first time you modified something, but it would be much more complicated and it would bury an O(n) (possibly expensive, possibly memory allocating) event inside an as
which feels like it should be O(1) and allocate no memory. So there's reasons not to do that.
Some day they may do it anyway to make things simpler on the caller, but there's a cost in both performance and complexity, and so it doesn't do it today and you need to do the map yourself.
If you want a much deeper dive into this stuff, with more details on how this box works (and less "pretend it's simpler than it is"), see Understanding Swift Performance from WWDC 2016.
Swift protocol for things that convert to and from String
This is how you extend RawRespresentable
to be conditionally LosslessStringConvertible
depending on its RawValue
:
extension RawRepresentable where RawValue: LosslessStringConvertible {
init?(_ rv: RawValue) {
self.init(rawValue: rv)
}
var description: String { return self.rawValue.description }
}
Here it is in action:
struct GenericThing<Id: LosslessStringConvertible> {
}
enum Tubbies: String, LosslessStringConvertible {
case dipsy
case laalaa
case po
}
let genericThing = GenericThing<Tubbies>()
print(Tubbies.po is LosslessStringConvertible) // => true
How to convert/cast from a protocol to a class in swift?
With Swift 1.2 / Xcode 6.3 Beta, this compiles:
var cellToReturn = cellProtocol as! UITableViewCell
As of Swift 1.1, You have to cast it to AnyObject
or Any
, then UITableViewCell
. I think this was a kind of bug.
var cellToReturn = cellProtocol as AnyObject as UITableViewCell
ADDED: It turns out that it's a problem of Optional
In this case, cellProtocol
is MyTableViewCellProtocol?
. you have to unwrap it first, then cast.
Try:
var cellToReturn = cellProtocol! as AnyObject as UITableViewCell
// ^
Cast Protocol to Class in Swift
You are on the right path with optional binding.
as?
is a variation of as!
that evaluates to an optional of the type to which you are casting. You can use this in conjunction with optional binding:
arr.forEach{ object in
if let a = object as? A { // (object as? A) is of type "A?", but we are unwrapping it
// a is of type A now
}
}
Can you enforce type conversion in a protocol without defining a property/method?
If I understand your question correctly – no, I don't think you can't define an "implicit" conversion that detects and uses a matching init
from a specific type. The only way to convert from one type to another in Swift is to explicitly call an init
for the "to" type that takes the "from" type, or a function or method on the "from" type that returns the "to" type. There's no way of implementing a protocol that says "use the init
for this type with other type, if one is available".
By the way, your ConvertibleToString
protocol is essentially a version of Printable
(with asString
in place of description
). So if what you want is to know if something is convertible to a string, you can just check for conformance to Printable
. Though note one gotcha – String
is not Printable
. You can use toString(thing)
to convert anything to a string, and it will use Printable
where available (and do nothing to convert strings), though this does have the side-effect of giving you a default for non-printable types that you may not want depending on your need.
Note you can require convertibility from something via a protocol:
protocol ConvertibleFromInt {
init(Int)
}
extension String: ConvertibleFromInt { }
extension UInt64: ConvertibleFromInt { }
func gimmeFromInt<T: ConvertibleFromInt>(i: Int) -> T {
return T(i)
}
let s: String = gimmeFromInt(5)
let ui: UInt64 = gimmeFromInt(5)
Swift P.Protocol vs P.Type
P.Protocol
is the metatype for the protocol P
, just like T.Type
is the metatype for the non-protocol type T
. There is no "conversions" going on.
So what is P.Type
then?
P.Type
is an existential metatype. There is no corresponding thing for non-protocol types. Say you want to store metatypes of concrete types that conform to P
, you can store it in P.Type
:
let x: P.Type = C.self
Note that P.Type
can only store metatypes of concrete types, and P.Protocol
can only store metatypes of protocols. To see why this division is significant, let's say P
defines the static method foo
, you can then call x.foo()
. This is guaranteed to work because P.Type
must have a concrete type, which will implement foo
. On the other hand, you can't call foo
on P.Protocol
, because there is no implementation of foo
in P
.
See also: https://swiftrocks.com/whats-type-and-self-swift-metatypes
Swift: convert array of actual type to array of protocol type
This Q&A explains the problem. I will suggest a fix that avoids creation of a new array: make your log
function generic, and add a type constraint on its type parameter, requiring it to conform to ToString
protocol:
func log<T:ToString>( values: [T]) {
values.forEach { print( $0.toString()) }
}
Now Swift lets you call your function with arrays of any type, as long as array elements conform to ToString
protocol.
Related Topics
Wkwebview Does Not Load Links to Pdfs
Make Code With Firebase Asynchronous
Swift Sphere Combine Star Data
How to Save Data from Cloud Firestore to a Variable in Swift
Try, Try! & Try? What's the Difference, and When to Use Each
Alamofire Asynchronous Completionhandler For Json Request
Determining If Swift Dictionary Contains Key and Obtaining Any of Its Values
How to Silence a Warning in Swift
Include Swiftui Views in Existing Uikit Application
Ios 15 Navigation Bar Transparent
Swap Rootviewcontroller With Animation
Generating Random Numbers With Swift
Swift Xcode Index Freezing or Slow
Swiftui - Is There a Popviewcontroller Equivalent in Swiftui
Module Compiled With Swift 3.0 Cannot Be Imported in Swift 3.0.1
How to Document the Parameters of a Function'S Closure Parameter in Swift 3