What is Swift enum byte representation?
The Swift ABI is still work in progress (expected to be fixed with Swift 4). The way enums are represented in memory is described here.
Your case is a "c-like enum" because is has...
- two or more cases
- no associated values
Quoting the ABI document:
the enum is laid out as an integer tag with the minimal number of bits to contain all of the cases. [...] The cases are assigned tag values in declaration order.
The crucial information here is the "minimal number of bits". This means that (for your case) instances should fit into two bits (as you have three cases). The rawValue 0x10
would need five bits—which would be in conflict with the ABI.
The compiler probably uses static tables to convert between instances of Enum
and their rawValue
(and back).
Here's an example that highlights this characteristic of the ABI:
enum Enum: UInt32
{
case A = 0
case B = 0xffffffff // value that does not fit into one byte
}
assert(sizeof(Enum.self) == 1)
Swift enum size when associated value is a reference type
From Type Layout: Single-Payload Enums:
If the data type's binary representation has extra inhabitants, that is, bit patterns with the size and alignment of the type but which do not form valid values of that type, they are used to represent the no-data cases, with extra inhabitants in order of ascending numeric value matching no-data cases in declaration order.
Your example with more cases:
enum Opt<T> {
case a, b, c, d, e, f, g, h, i, j, k
case l, m, n, o, p, q, r, s, t, u, v
case some(T)
}
class Person {
var name: String
init(name: String) { self.name = name }
}
print(unsafeBitCast(Opt<Person>.a, to: UnsafeRawPointer.self))
// 0x0000000000000000
print(unsafeBitCast(Opt<Person>.b, to: UnsafeRawPointer.self))
// 0x0000000000000002
print(unsafeBitCast(Opt<Person>.v, to: UnsafeRawPointer.self))
// 0x000000000000002a
let p = Person(name: "Bob")
print(unsafeBitCast(Opt.some(p), to: UnsafeRawPointer.self))
// 0x00006030000435d0
Apparently, 0x0
, 0x2
, ..., 0x2a
are invalid bit patterns for a pointer, and therefore used for the additional cases.
The precise algorithm seems to be undocumented, one probably would have to inspect the Swift compiler source code.
Declaring and using a bit field enum in Swift
Updated for Swift 2/3
Since swift 2, a new solution has been added as "raw option set" (see: Documentation), which is essentially the same as my original response, but using structs that allow arbitrary values.
This is the original question rewritten as an OptionSet
:
struct MyOptions: OptionSet
{
let rawValue: UInt8
static let One = MyOptions(rawValue: 0x01)
static let Two = MyOptions(rawValue: 0x02)
static let Four = MyOptions(rawValue: 0x04)
static let Eight = MyOptions(rawValue: 0x08)
}
let m1 : MyOptions = .One
let combined : MyOptions = [MyOptions.One, MyOptions.Four]
Combining with new values can be done exactly as Set
operations (thus the OptionSet part), .union
, likewise:
m1.union(.Four).rawValue // Produces 5
Same as doing One | Four
in its C-equivalent. As for One & Mask != 0
, can be specified as a non-empty intersection
// Equivalent of A & B != 0
if !m1.intersection(combined).isEmpty
{
// m1 belongs is in combined
}
Weirdly enough, most of the C-style bitwise enums have been converted to their OptionSet
equivalent on Swift 3, but Calendar.Compontents
does away with a Set<Enum>
:
let compontentKeys : Set<Calendar.Component> = [.day, .month, .year]
Whereas the original NSCalendarUnit
was a bitwise enum. So both approaches are usable (thus the original response remains valid)
Original Response
I think the best thing to do, is to simply avoid the bitmask syntax until the Swift devs figure out a better way.
Most of the times, the problem can be solved using an enum
and and a Set
enum Options
{
case A, B, C, D
}
var options = Set<Options>(arrayLiteral: .A, .D)
An and check (options & .A
) could be defined as:
options.contains(.A)
Or for multiple "flags" could be:
options.isSupersetOf(Set<Options>(arrayLiteral: .A, .D))
Adding new flags (options |= .C
):
options.insert(.C)
This also allows for using all the new stuff with enums: custom types, pattern matching with switch case, etc.
Of course, it doesn't have the efficiency of bitwise operations, nor it would be compatible with low level things (like sending bluetooth commands), but it's useful for UI elements that the overhead of the UI outweighs the cost of the Set operations.
What is the equivalent data type for byte in iOS swift?
The data type is Unsigned Int 8 (UInt8).
var byte:UInt8 = 0xAF
For a string of bytes:
var bytes:[UInt8] = [0xAF,0xAB]
For the bytes from data:
var data = Data()
var bytes = data.bytes //[UInt8]
Raw value for enum case must be a literal
That's because 1 << 0
isn't a literal. You can use a binary literal which is a literal and is allowed there:
enum GestureDirection:UInt {
case Up = 0b000
case Down = 0b001
case Left = 0b010
case Right = 0b100
}
Enums only support raw-value-literal
s which are either numeric-literal
(numbers) string-literal
(strings) or boolean-literal
(bool) per the language grammar.
Instead as a workaround and still give a good indication of what you're doing.
How to enumerate an enum with String type?
Swift 4.2+
Starting with Swift 4.2 (with Xcode 10), just add protocol conformance to CaseIterable
to benefit from allCases
. To add this protocol conformance, you simply need to write somewhere:
extension Suit: CaseIterable {}
If the enum is your own, you may specify the conformance directly in the declaration:
enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }
Then the following code will print all possible values:
Suit.allCases.forEach {
print($0.rawValue)
}
Compatibility with earlier Swift versions (3.x and 4.x)
If you need to support Swift 3.x or 4.0, you may mimic the Swift 4.2 implementation by adding the following code:
#if !swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif
Swift: Convert enum value to String?
Not sure in which Swift version this feature was added, but right now (Swift 2.1) you only need this code:
enum Audience : String {
case public
case friends
case private
}
let audience = Audience.public.rawValue // "public"
When strings are used for raw values, the implicit value for each case
is the text of that case’s name.[...]
enum CompassPoint : String {
case north, south, east, west
}
In the example above, CompassPoint.south has an implicit raw value of
"south", and so on.You access the raw value of an enumeration case with its rawValue
property:let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"
Source.
Related Topics
Why Would One Use Nested Classes
Iocreateplugininterfaceforservice Returns Mysterious Error
How to Draw a Line Between Two Points Over an Image in Swift 3
How to Fix Cannot Find 'Firebaseapp' in Scope
How to Create an iOS Liveview in Xcode 8/Swift 3
Swift Display Image UIimageview
Difference Between Sort and Sortinplace in Swift 2
Override UIgesturerecognizer Touchesbegan
Module Compiled with Swift X.1 Cannot Be Imported in Swift X.0.2
Ckasset in Server Record Contains No Fileurl, Cannot Even Check for Nil
How to Use Crc32 from Zlib in Swift (Xcode 9)
How to Cast from Cftyperef to Axuielement in Swift
Swift Protocol Extension Implementing Another Protocol with Shared Associated Type
How to Test a Url and Get a Status Code in Swift 3
Swift Cannot Invoke '*' with an Argument List of Type '(Int, Int)'