Updating value of Enum - swift

I have an enum that I use to populate a collection View and data changes based on API call and when this call is made, I want to change the subTitle value here is what I have currently
enum BalanceType: String, CaseIterable {
case ledger
case available
var backgroundImage: UIImage {
switch self {
case .ledger:
return R.image.walletBgNonWithdrawable()!
case .available:
return R.image.walletBgWithdrawable()!
}
}
var title: String {
switch self {
case .ledger:
return "Contribution Ledger Balance"
case .available:
return "My Available Balance"
}
}
var subTitle: String {
switch self {
case .ledger:
return Util.df2so(LedgerBalanceModel.currentWallet()?.totalLedgerBalance ?? 0)
case .available:
return Util.df2so((LedgerBalanceModel.currentWallet()?.totalLedgerBalance ?? 0) - (LedgerBalanceModel.currentWallet()?.totalMinBalance ?? 0))
}
}
}
my call that should update the value is
func showLedgerBal(_ data: LedgerBalanceModel) {
collectionView.reloadData()
}

Related

Function declares an opaque return type 'some View', but the return statements in its body do not have matching underlying types

I am getting the error where var view: some View{.
enum HomeButtons: Int, Hashable, CaseIterable{
case registerSignal = 1
case setAlarm = 2
case tV = 3
case test = 4
var image: String{
switch self{
case .registerSignal:
return "wave.3.backward"
case .setAlarm:
return "alarm.fill"
case .tV:
return "tv.fill"
case .test:
return "av.remote.fill"
}
}
var text: String{
switch self{
case .registerSignal:
return "Register Signal for TV"
case .setAlarm:
return "Set up Alarm"
case .tV:
return "TV and Sequences"
case .test:
return "Test Device"
}
}
var view: some View{ <------- Error is displayed here
switch self{
case .registerSignal:
return RegisterView(title: self.text)
case .setAlarm:
return Text("Set up Alarm")
case .tV:
return Text("TV and Sequences")
case .test:
return Text("Test Device")
}
}
}
struct RegisterView: View{
var title: String
var body: some View{
ScrollView{
ForEach(getTVList(), id: \.TVID){ TV in
NavigationLink(value: TV.TVID){
Text(TV.name)
}
}
}
.background(Color("ToledoGolden"))
.foregroundColor(.accentColor)
.navigationTitle(title)
}
}
I tried changing var view: some View to var view: any View the error went away but where I was calling HomeButtons.view I got this error message: Type 'any View' cannot conform to 'View'
You have to make the variable an #ViewBuilder and remove the return
enum HomeButtons: Int, Hashable, CaseIterable{
case registerSignal = 1
case setAlarm = 2
case tV = 3
case test = 4
var image: String{
switch self{
case .registerSignal:
return "wave.3.backward"
case .setAlarm:
return "alarm.fill"
case .tV:
return "tv.fill"
case .test:
return "av.remote.fill"
}
}
var text: String{
switch self{
case .registerSignal:
return "Register Signal for TV"
case .setAlarm:
return "Set up Alarm"
case .tV:
return "TV and Sequences"
case .test:
return "Test Device"
}
}
#ViewBuilder var view: some View{
switch self{
case .registerSignal:
RegisterView(title: self.text)
case .setAlarm:
Text("Set up Alarm")
case .tV:
Text("TV and Sequences")
case .test:
Text("Test Device")
}
}
}

Is there a clean way of making an enum with associated value conform to rawRepresentable?

I have this in my code and it works, however if I have other enums (not necessarily color) with a long list it gets tiresome. Is there a better way of having an enum with an associated value that also conforms to RawRepresentable?
public enum IconColor {
case regular
case error
case warning
case success
case custom(String)
public var value: Color {
return loadColor(self.rawValue)
}
}
extension IconColor: RawRepresentable {
public var rawValue: String {
switch self {
case .regular: return "icon_regular"
case .error: return "icon_error"
case .warning: return "icon_warning"
case .success: return "icon_success"
case .custom(let value): return value
}
}
public init(rawValue: String) {
switch rawValue {
case "icon_regular": self = .regular
case "icon_error": self = .error
case "icon_warning": self = .warning
case "icon_success": self = .success
default: self = .custom(rawValue)
}
}
}
There's not a general solution.
public var rawValue: String {
switch self {
case .custom(let value): return value
default: return "icon_\(self)"
}
}
public init(rawValue: String) {
self =
[.regular, .error, .warning, .success]
.first { rawValue == $0.rawValue }
?? .custom(rawValue)
}

how to use Codable with Class enum

I feel like I'm going way too far for what should really be a simple thing. With the below code, the error that I get is: Cannot invoke 'decode' with an argument list of type '(GameOfLife.Cell, forKey: GameOfLife.Cell.CodingKeys)'
extension GameOfLife {
enum Cell: Equatable, Codable {
case alive
case born
case dying
case dead
var isAlive: Bool {
switch self {
case .alive, .born: return true
case .dying, .dead: return false
}
}
var isDead: Bool {
switch self {
case .alive, .born: return false
case .dying, .dead: return true
}
}
func equalTo(_ rhs: Cell) -> Bool {
switch (self) {
case .alive, .born:
return rhs.isAlive
case .dead, .dying:
return rhs.isDead
}
}
init(_ living: Bool) {
self = living ? .alive : .dead
}
enum CodingKeys: CodingKey {
case alive
case born
case dying
case dead
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
let leftValue = try container.decode(GameOfLife.Cell.alive, forKey: CodingKeys.alive)
self = GameOfLife.Cell.alive
} catch {
let leftValue = try container.decode(GameOfLife.Cell.born, forKey: CodingKeys.born)
self = GameOfLife.Cell.born
} catch {
let leftValue = try container.decode(GameOfLife.Cell.dying, forKey: CodingKeys.dying)
self = GameOfLife.Cell.dying
} catch {
let leftValue = try container.decode(GameOfLife.Cell.dead, forKey: CodingKeys.dead)
self = GameOfLife.Cell.dead
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .alive:
try container.encode("alive", forKey: .alive)
case .born:
try container.encode("born", forKey: .born)
case .dying:
try container.encode("dying", forKey: .dying)
case .dead:
try container.encode("dead", forKey: .dead)
}
}
}
}
The first parameter of decode( is the expected type of the decoded object. As you are encoding the enum cases a String, it's supposed to be String
let leftValue = try container.decode(String.self, forKey: .alive) // The compiler can infer the type `CodingKeys`
However the entire init(from method makes no sense. If an error occurs inside a catch expression it is not going to be caught in the subsequent catch expression.
To encode an enum case as String just declare the raw type of the enum as String and delete the CodingKeys and the init(from and encode(to methods. And if you want to adopt Equatable you have to implement ==
extension GameOfLife : Codable {
enum Cell: String, Equatable, Codable {
case alive, born, dying, dead
var isAlive: Bool {
switch self {
case .alive, .born: return true
case .dying, .dead: return false
}
}
// isDead can be simplified
var isDead: Bool {
return !isAlive
}
static func == (lhs: Cell, rhs: Cell) -> Bool {
switch (lhs.isAlive, rhs.isAlive) {
case (true, true), (false, false): return true
default: return false
}
}
init(_ living: Bool) {
self = living ? .alive : .dead
}
}
}

Extending swift optional for default values

I'm trying to extend Swift's Optional type with default values. Providing empty values in API requests should raise an exception. I've done this for the String type, but I can't achieve the same result with the Integer type:
extension Optional where Wrapped == String {
var unwrappedValue: String {
get {
switch self {
case .some(let value):
return value
case .none:
return ""
}
}
}
}
The Integer version is throwing the following Error:
Protocol 'Integer' can only be used as a generic constraint because it
has Self or associated type requirements
extension Optional where Wrapped == Integer {
var unwrappedValue: Integer {
get {
switch self {
case .some(let value):
return value
case .none:
return 0
}
}
}
}
If you use this for a lot of Types you might want to consider the following addition to the answer of Leo Dabus:
protocol Defaultable {
static var defaultValue: Self { get }
}
extension Optional where Wrapped: Defaultable {
var unwrappedValue: Wrapped { return self ?? Wrapped.defaultValue }
}
This way you can extend your types very easily:
extension Int: Defaultable {
static var defaultValue: Int { return 0 }
}
extension String: Defaultable {
static var defaultValue: String { return "" }
}
extension Array: Defaultable {
static var defaultValue: Array<Element> { return [] }
}
And usage goes like this:
let optionalInt: Int? = 10 // Optional(10)
let unwrappedInt = optionalInt.unwrappedValue // 10
let optionalString: String? = "Hello" // Optional("Hello")
let unwrappedString = optionalString.unwrappedValue // "Hello"
let optionalArray: [Int]? = nil // nil
let unwrappedArray = optionalArray.unwrappedValue // []
You just need to return Wrapped instead of Integer
extension Optional where Wrapped: Integer {
var unwrappedValue: Wrapped {
switch self {
case .some(let value):
return value
case .none:
return 0
}
}
}
or simply
extension Optional where Wrapped: Integer {
var safelyUnwrapped: Wrapped { return self ?? 0 }
}
let optionalInt = Int("10")
let unwrappedValue = optionalInt.safelyUnwrapped // 10
You can also achieve using below code:
extension Optional {
func defaultValue(_ val: Wrapped) -> Wrapped { return self ?? val }
}
var str: String?
str.defaultValue("User")
var a: Int?
a.defaultValue(2)
This will work for both data types.

Swift 2 to 3 Migration for Swift Sequence Protocol

I'm attempting to convert the following code from this library (https://github.com/dankogai/swift-json) into Swift 3 Compatible code.
I'm having a tough time figuring out how to convert the Sequence protocol used in Swift 2 with the correct version for Swift 3. I can't find any documentation on Swift 2 Sequence protocol changes as compared to 3.
Here is the code that I currently have converted as much as possible to Swift 3
extension JSON : Sequence {
public func generate()->AnyIterator<(AnyObject,JSON)> {
switch _value {
case let o as NSArray:
var i = -1
return AnyIterator {
i=i+1
if i == o.count { return nil }
return (i as AnyObject, JSON(o[i]))
}
case let o as NSDictionary:
var ks = Array(o.allKeys.reversed())
return AnyIterator {
if ks.isEmpty { return nil }
if let k = ks.removeLast() as? String {
return (k as AnyObject, JSON(o.value(forKey: k)!))
} else {
return nil
}
}
default:
return AnyIterator{ nil }
}
}
public func mutableCopyOfTheObject() -> AnyObject {
return _value.mutableCopy as AnyObject
}
}
The error I'm getting in specifics is in attached image.
If you want to play around with it the entire code is rather short for the JSON library. Here it is below:
//
// json.swift
// json
//
// Created by Dan Kogai on 7/15/14.
// Copyright (c) 2014 Dan Kogai. All rights reserved.
//
import Foundation
/// init
public class JSON {
public let _value:AnyObject
/// unwraps the JSON object
public class func unwrap(obj:AnyObject) -> AnyObject {
switch obj {
case let json as JSON:
return json._value
case let ary as NSArray:
var ret = [AnyObject]()
for v in ary {
ret.append(unwrap(obj: v as AnyObject))
}
return ret as AnyObject
case let dict as NSDictionary:
var ret = [String:AnyObject]()
for (ko, v) in dict {
if let k = ko as? String {
ret[k] = unwrap(obj: v as AnyObject)
}
}
return ret as AnyObject
default:
return obj
}
}
/// pass the object that was returned from
/// NSJSONSerialization
public init(_ obj:Any) { self._value = JSON.unwrap(obj: obj as AnyObject) }
/// pass the JSON object for another instance
public init(_ json:JSON){ self._value = json._value }
}
/// class properties
extension JSON {
public typealias NSNull = Foundation.NSNull
public typealias NSError = Foundation.NSError
public class var null:NSNull { return NSNull() }
/// constructs JSON object from data
public convenience init(data:NSData) {
var err:NSError?
var obj:Any?
do {
obj = try JSONSerialization.jsonObject(
with: data as Data, options:[])
} catch let error as NSError {
err = error
obj = nil
}
self.init(err != nil ? err! : obj!)
}
/// constructs JSON object from string
public convenience init(string:String) {
let enc:String.Encoding = String.Encoding.utf8
self.init(data: string.data(using: enc)! as NSData)
}
/// parses string to the JSON object
/// same as JSON(string:String)
public class func parse(string:String)->JSON {
return JSON(string:string)
}
/// constructs JSON object from the content of NSURL
public convenience init(nsurl:NSURL) {
var enc:String.Encoding = String.Encoding.utf8
do {
let str = try NSString(contentsOf:nsurl as URL, usedEncoding:&enc.rawValue)
self.init(string:str as String)
} catch let err as NSError {
self.init(err)
}
}
/// fetch the JSON string from NSURL and parse it
/// same as JSON(nsurl:NSURL)
public class func fromNSURL(nsurl:NSURL) -> JSON {
return JSON(nsurl:nsurl)
}
/// constructs JSON object from the content of URL
public convenience init(url:String) {
if let nsurl = NSURL(string:url) as NSURL? {
self.init(nsurl:nsurl)
} else {
self.init(NSError(
domain:"JSONErrorDomain",
code:400,
userInfo:[NSLocalizedDescriptionKey: "malformed URL"]
)
)
}
}
/// fetch the JSON string from URL in the string
public class func fromURL(url:String) -> JSON {
return JSON(url:url)
}
/// does what JSON.stringify in ES5 does.
/// when the 2nd argument is set to true it pretty prints
public class func stringify(obj:AnyObject, pretty:Bool=false) -> String! {
if !JSONSerialization.isValidJSONObject(obj) {
let error = JSON(NSError(
domain:"JSONErrorDomain",
code:422,
userInfo:[NSLocalizedDescriptionKey: "not an JSON object"]
))
return JSON(error).toString(pretty: pretty)
}
return JSON(obj).toString(pretty: pretty)
}
}
/// instance properties
extension JSON {
/// access the element like array
public subscript(idx:Int) -> JSON {
switch _value {
case _ as NSError:
return self
case let ary as NSArray:
if 0 <= idx && idx < ary.count {
return JSON(ary[idx])
}
return JSON(NSError(
domain:"JSONErrorDomain", code:404, userInfo:[
NSLocalizedDescriptionKey:
"[\(idx)] is out of range"
]))
default:
return JSON(NSError(
domain:"JSONErrorDomain", code:500, userInfo:[
NSLocalizedDescriptionKey: "not an array"
]))
}
}
/// access the element like dictionary
public subscript(key:String)->JSON {
switch _value {
case _ as NSError:
return self
case let dic as NSDictionary:
if let val:Any = dic[key] { return JSON(val) }
return JSON(NSError(
domain:"JSONErrorDomain", code:404, userInfo:[
NSLocalizedDescriptionKey:
"[\"\(key)\"] not found"
]))
default:
return JSON(NSError(
domain:"JSONErrorDomain", code:500, userInfo:[
NSLocalizedDescriptionKey: "not an object"
]))
}
}
/// access json data object
public var data:AnyObject? {
return self.isError ? nil : self._value
}
/// Gives the type name as string.
/// e.g. if it returns "Double"
/// .asDouble returns Double
public var type:String {
switch _value {
case is NSError: return "NSError"
case is NSNull: return "NSNull"
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C": return "Bool"
case "q", "l", "i", "s": return "Int"
case "Q", "L", "I", "S": return "UInt"
default: return "Double"
}
case is NSString: return "String"
case is NSArray: return "Array"
case is NSDictionary: return "Dictionary"
default: return "NSError"
}
}
/// check if self is NSError
public var isError: Bool { return _value is NSError }
/// check if self is NSNull
public var isNull: Bool { return _value is NSNull }
/// check if self is Bool
public var isBool: Bool { return type == "Bool" }
/// check if self is Int
public var isInt: Bool { return type == "Int" }
/// check if self is UInt
public var isUInt: Bool { return type == "UInt" }
/// check if self is Double
public var isDouble: Bool { return type == "Double" }
/// check if self is any type of number
public var isNumber: Bool {
if let o = _value as? NSNumber {
let t = String(cString:o.objCType)
return t != "c" && t != "C"
}
return false
}
/// check if self is String
public var isString: Bool { return _value is NSString }
/// check if self is Array
public var isArray: Bool { return _value is NSArray }
/// check if self is Dictionary
public var isDictionary: Bool { return _value is NSDictionary }
/// check if self is a valid leaf node.
public var isLeaf: Bool {
return !(isArray || isDictionary || isError)
}
/// gives NSError if it holds the error. nil otherwise
public var asError:NSError? {
return _value as? NSError
}
/// gives NSNull if self holds it. nil otherwise
public var asNull:NSNull? {
return _value is NSNull ? JSON.null : nil
}
/// gives Bool if self holds it. nil otherwise
public var asBool:Bool? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C": return Bool(o.boolValue)
default:
return nil
}
default: return nil
}
}
/// gives Int if self holds it. nil otherwise
public var asInt:Int? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Int(o.int64Value)
}
default: return nil
}
}
/// gives Int32 if self holds it. nil otherwise
public var asInt32:Int32? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Int32(o.int64Value)
}
default: return nil
}
}
/// gives Int64 if self holds it. nil otherwise
public var asInt64:Int64? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Int64(o.int64Value)
}
default: return nil
}
}
/// gives Float if self holds it. nil otherwise
public var asFloat:Float? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Float(o.floatValue)
}
default: return nil
}
}
/// gives Double if self holds it. nil otherwise
public var asDouble:Double? {
switch _value {
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return nil
default:
return Double(o.doubleValue)
}
default: return nil
}
}
// an alias to asDouble
public var asNumber:Double? { return asDouble }
/// gives String if self holds it. nil otherwise
public var asString:String? {
switch _value {
case let o as NSString:
return o as String
default: return nil
}
}
/// if self holds NSArray, gives a [JSON]
/// with elements therein. nil otherwise
public var asArray:[JSON]? {
switch _value {
case let o as NSArray:
var result = [JSON]()
for v:Any in o { result.append(JSON(v)) }
return result
default:
return nil
}
}
/// if self holds NSDictionary, gives a [String:JSON]
/// with elements therein. nil otherwise
public var asDictionary:[String:JSON]? {
switch _value {
case let o as NSDictionary:
var result = [String:JSON]()
for (ko, v): (Any, Any) in o {
if let k = ko as? String {
result[k] = JSON(v)
}
}
return result
default: return nil
}
}
/// Yields date from string
public var asDate:NSDate? {
if let dateString = _value as? String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ"
return dateFormatter.date(from: dateString) as NSDate?
}
return nil
}
/// gives the number of elements if an array or a dictionary.
/// you can use this to check if you can iterate.
public var count:Int {
switch _value {
case let o as NSArray: return o.count
case let o as NSDictionary: return o.count
default: return 0
}
}
public var length:Int { return self.count }
// gives all values content in JSON object.
public var allValues:JSON{
if(self._value.allValues == nil) {
return JSON([])
}
return JSON(self._value.allValues)
}
// gives all keys content in JSON object.
public var allKeys:JSON{
if(self._value.allKeys == nil) {
return JSON([])
}
return JSON(self._value.allKeys)
}
}
extension JSON : Sequence {
public func generate()->AnyIterator<(AnyObject,JSON)> {
switch _value {
case let o as NSArray:
var i = -1
return AnyIterator {
i=i+1
if i == o.count { return nil }
return (i as AnyObject, JSON(o[i]))
}
case let o as NSDictionary:
var ks = Array(o.allKeys.reversed())
return AnyIterator {
if ks.isEmpty { return nil }
if let k = ks.removeLast() as? String {
return (k as AnyObject, JSON(o.value(forKey: k)!))
} else {
return nil
}
}
default:
return AnyIterator{ nil }
}
}
public func mutableCopyOfTheObject() -> AnyObject {
return _value.mutableCopy as AnyObject
}
}
extension JSON : CustomStringConvertible {
/// stringifies self.
/// if pretty:true it pretty prints
public func toString(pretty:Bool=false)->String {
switch _value {
case is NSError: return "\(_value)"
case is NSNull: return "null"
case let o as NSNumber:
switch String(cString:o.objCType) {
case "c", "C":
return o.boolValue.description
case "q", "l", "i", "s":
return o.int64Value.description
case "Q", "L", "I", "S":
return o.uint64Value.description
default:
switch o.doubleValue {
case 0.0/0.0: return "0.0/0.0" // NaN
case -1.0/0.0: return "-1.0/0.0" // -infinity
case +1.0/0.0: return "+1.0/0.0" // infinity
default:
return o.doubleValue.description
}
}
case let o as NSString:
return o.debugDescription
default:
let opts = pretty ? JSONSerialization.WritingOptions.prettyPrinted : JSONSerialization.WritingOptions()
if let data = (try? JSONSerialization.data(
withJSONObject: _value, options:opts)) as NSData? {
if let result = NSString(
data:data as Data, encoding:String.Encoding.utf8.rawValue
) as? String {
return result
}
}
return "YOU ARE NOT SUPPOSED TO SEE THIS!"
}
}
public var description:String { return toString() }
}
extension JSON : Equatable {}
public func ==(lhs:JSON, rhs:JSON)->Bool {
// print("lhs:\(lhs), rhs:\(rhs)")
if lhs.isError || rhs.isError { return false }
else if lhs.isLeaf {
if lhs.isNull { return lhs.asNull == rhs.asNull }
if lhs.isBool { return lhs.asBool == rhs.asBool }
if lhs.isNumber { return lhs.asNumber == rhs.asNumber }
if lhs.isString { return lhs.asString == rhs.asString }
}
else if lhs.isArray {
for i in 0..<lhs.count {
if lhs[i] != rhs[i] { return false }
}
return true
}
else if lhs.isDictionary {
for (k, v) in lhs.asDictionary! {
if v != rhs[k] { return false }
}
return true
}
fatalError("JSON == JSON failed!")
}
In Swift 3, generate() has been renamed to makeIterator(). Changing the name of your function should fix the problem. (Note that other names have also changed, like AnyGenerator → AnyIterator, but it looks like that one has already been taken care of in your code.)
This change was implemented as part of SE-0006: Apply API Guidelines to the Standard Library.