I need to subtract a DispatchTimeInterval from an NSTimeInterval (or Double).
Is there a standard way to convert a DispatchTimeInterval to an NSTimeInterval?
DispatchTimeInterval is a enum:
public enum DispatchTimeInterval : Equatable {
case seconds(Int)
case milliseconds(Int)
case microseconds(Int)
case nanoseconds(Int)
case never
}
You can initialize DispatchTimeInterval using:
let tenSeconds: DispatchTimeInterval = .seconds(10)
let tenNanoseconds: DispatchTimeInterval = .nanoseconds(10)
To get values from enum you need to match value with a case values in enum
if case .seconds(let value) = tenSeconds {
print("DispatchTimeInterval is seconds \(value)")
} else if case .nanoseconds(let value) = tenNanoseconds {
print("DispatchTimeInterval is seconds \(value)")
}
Converting function might be look following:
func toDouble(_ interval: DispatchTimeInterval) -> Double? {
var result: Double? = 0
switch interval {
case .seconds(let value):
result = Double(value)
case .milliseconds(let value):
result = Double(value)*0.001
case .microseconds(let value):
result = Double(value)*0.000001
case .nanoseconds(let value):
result = Double(value)*0.000000001
case .never:
result = nil
}
return result
}
More about Enumeration see in Apple Documentation
UPDATE:
Create extension to DispatchTimeInterval
extension DispatchTimeInterval {
func toDouble() -> Double? {
var result: Double? = 0
switch self {
case .seconds(let value):
result = Double(value)
case .milliseconds(let value):
result = Double(value)*0.001
case .microseconds(let value):
result = Double(value)*0.000001
case .nanoseconds(let value):
result = Double(value)*0.000000001
case .never:
result = nil
}
return result
}
}
A swifty solution would be to create a TimeInterval extension and add a failable initializer with a DispatchTimeInterval parameter in it. The following Swift 5 code shows how to implement it:
import Foundation
extension TimeInterval {
init?(dispatchTimeInterval: DispatchTimeInterval) {
switch dispatchTimeInterval {
case .seconds(let value):
self = Double(value)
case .milliseconds(let value):
self = Double(value) / 1_000
case .microseconds(let value):
self = Double(value) / 1_000_000
case .nanoseconds(let value):
self = Double(value) / 1_000_000_000
case .never:
return nil
}
}
}
Usage:
let dispatchTimeInterval = DispatchTimeInterval.seconds(5)
let timeInterval = TimeInterval(dispatchTimeInterval: dispatchTimeInterval)
print(String(describing: timeInterval)) // Optional(5.0)
let dispatchTimeInterval = DispatchTimeInterval.milliseconds(30)
let timeInterval = TimeInterval(dispatchTimeInterval: dispatchTimeInterval)
print(String(describing: timeInterval)) // Optional(0.03)
Related
I'm having an enum that I'm trying to initialize to case twentyFourHours like this:
enum Duration: TimeInterval {
case twentyFourHours
var durationInSeconds: TimeInterval {
switch self {
case .twentyFourHours:
return TimeInterval.init(86400)
}
}
var durationInHours: Int {
switch self {
case .twentyFourHours:
return 24
}
}
}
let interval = TimeInterval.init(86400)
guard let duration = Duration.init(rawValue: interval) else { throw ChallengeError.invalidDuration }
But I always get nil. Does anyone know why?
Seems like a basic thing I already should know!
Try this
enum Duration: TimeInterval {
case twentyFourHours = 86400
var durationInSeconds: TimeInterval {
return self.rawValue
}
var durationInHours: Int {
return Int(self.rawValue / 3600)
}
}
This equals to:
Duration(1234) // <- nil
Duration(86400) // <- .twentyFourHours
You need to specify the rawValue if it's something other than 0, TimeInterval is a typealias for type Double and it defaults the first case rawValue to 0 if not specified.
enum Duration: TimeInterval {
case twentyFourHours = 86400
//...
}
let interval: TimeInterval = 86400
let duration = Duration(rawValue: interval) // and then you can initialize like this
When I try to access the value of "value" for example to use it in a label.text, I get an error
Cannot assign value of type 'MyValue?' to type 'String?'
When I print the value to the terminal, it says ...
unknown context at 0x109d06188).MyValue.string...
How can solve this problem?
struct Root: Codable {
let description,id: String
let group,groupDescription: String?
let name: String
let value: MyValue
enum CodingKeys: String, CodingKey {
case description = "Description"
case group = "Group"
case groupDescription = "GroupDescription"
case id = "Id"
case name = "Name"
case value = "Value"
}
}
enum MyValue: Codable {
case string(String)
case innerItem(InnerItem)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
if let x = try? container.decode(InnerItem.self) {
self = .innerItem(x)
return
}
throw DecodingError.typeMismatch(MyValue.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let x):
try container.encode(x)
case .innerItem(let x):
try container.encode(x)
}
}
}
You can get string values for your label by conforming to rawRepresentable protocol:
enum MyValue: Codable, RawRepresentable {
var rawValue: String {
switch self {
case .string(let stringVal):
return stringVal
case .innerItem(let myVal):
return String(describing: myVal)
}
}
typealias RawValue = String
init?(rawValue: String) {
return nil
}
case string(String)
case innerItem(InnerItem)
}
let myVal = MyValue.string("testString")
var strVal: String = myVal.rawValue // testString
To get the associated values in the enum you could add two computed properties in MyValue
var stringValue : String? {
guard case .string(let string) = self else { return nil }
return string
}
var innerItemValue : InnerItem? {
guard case .innerItem(let innerItem) = self else { return nil }
return innerItem
}
Or switch on value like in the encode method
switch root.value {
case .string(let string): // do something with `string`
case .innerItem(let innerItem): // do something with `innerItem`
}
Or simply use if case
if case .string(let string) = root.value { someLabel.text = string }
Suppose we have an enum and want to enumerate over it :).
If it has Int rawValue we can be provided with next and previous items using computed vars like this.
enum Fidelity: Int, CaseIterable {
case pixel
case point
case average
case datapoint
var previousFidelity: Fidelity {
return Fidelity(rawValue: rawValue - 1) ?? .pixel
}
var nextFidelity: Fidelity {
return Fidelity(rawValue: rawValue + 1) ?? .datapoint
}
}
I went further and created and extension for CaseIterable which allows next() and previous() for a wide range of types.
// Let's test Swift 4.2 for enumerating enum
// Too complex, not very efficient, but interesting
extension CaseIterable where Self: Equatable {
func next() -> Self? {
let all = Self.allCases
let idx = all.index(of: self)!
let next = all.index(after: idx)
return (next == all.endIndex) ? nil : all[next]
}
func previous() -> Self? {
let all_reversed = Self.allCases.reversed()
let idx = all_reversed.index(of: self)!
let next = all_reversed.index(after: idx)
return (next == all_reversed.endIndex) ? nil : all_reversed[next]
}
}
The question is how efficient or inefficient my solutions are (i.e. speed, memory)?
Are there any ideas for doing the same or similar things, perhaps offset(by: ).
You can implement previous() using offsetBy this way:
func previous() -> Self? {
let all = Self.allCases
var idx = all.index(of: self)!
if idx == all.startIndex {
return nil
} else {
all.formIndex(&idx, offsetBy: -1)
return all[idx]
}
}
You can combine both next() and previous() in a more generic offset function:
extension CaseIterable where Self: Equatable {
func advanced(by n: Int) -> Self? {
let all = Self.allCases
let idx = all.index(of: self)!
//An enum with a raw type has at least one case
let lastIndex = all.index(all.endIndex, offsetBy: -1)
let limit = n > 0 ? lastIndex : all.startIndex
if let newIndex = all.index(idx, offsetBy: n, limitedBy: limit) {
return all[newIndex]
} else {
return nil
}
}
}
And use it like so
let average = Fidelity.average //average
average.advanced(by: 1) //datapoint
average.advanced(by: 2) //nil
average.advanced(by: -3) //pixel
I have a function where I parse a String into a Bool, Double or Int before falling back to a String. Currently I use a if-else conditions like this
func parse(stringValue: String) {
if let value = Bool(stringValue) {
// do something with a Bool
print(value)
} else if let value = Int(stringValue) {
// do something with a Int
print("\(stringValue) is Int: \(value)")
} else if let value = Double(stringValue) {
// do something with a Double
print("\(stringValue) is Double: \(value)")
} else {
// do something with a String
print("String: \(stringValue)")
}
}
This is ok but my personal preference is to use switch statements in Swift but I don't know how to do so without force unwrapping:
func parse(stringValue: String) {
switch stringValue {
case _ where Bool(stringValue) != nil:
let value = Bool(stringValue)!
// do something with Bool
case _ where Int(stringValue) != nil:
let value = Int(stringValue)!
// do something with Int
case _ where Double(stringValue) != nil:
let value = Double(stringValue)!
// do something with Double
default:
// do something with String
}
}
How can I capture the result of the where so that I can use it in the case scope?
Using the PartialKeyPath API, how can you access a value of a key path's reference? For example, this works for non-optional values, but not with Optional values.
The issue I'm having is that self[keyPath: keyPath] returns a non-optional Any value.
struct Element {
let name: String
let mass: Double?
func stringValue(_ keyPath: PartialKeyPath<Element>) -> String {
let value = self[keyPath: keyPath]
switch value {
case let string as String:
return string.capitalized
case nil:
return "N/A"
case let value:
return String(describing: value)
}
}
}
let element = Element(name: "Helium", mass: 4.002602)
let string = element.stringValue(\Element.mass) /* Optional(4.002602) */
The result is that case nil is never executed and the last case is being printed as Optional(value).
How can I unwrap value properly to extract the optional?
The solution was to use Mirror to unwrap the optional which seems less than optimal. Looking forward to better Reflection support in Swift!
func unwrap(_ value: Any) -> Any? {
let mirror = Mirror(reflecting: value)
if mirror.displayStyle != .optional {
return value
}
if let child = mirror.children.first {
return child.value
} else {
return nil
}
}
struct Element {
let name: String
let mass: Double?
func stringValue(_ keyPath: PartialKeyPath<AtomicElement>) -> String {
guard let value = unwrap(self[keyPath: keyPath]) else {
return "N/A"
}
switch value {
case let string as String:
return string.capitalized
default:
return String(describing: value)
}
}
}
let element = Element(name: "Helium", mass: 4.002602)
let string = element.stringValue(\Element.mass) /* 4.002602 */