Enum case 'case' is not a member of type 'Type' - ios

I'm a complete new-be in programming and have just started learning swift and iOS development.
The idea is to create a kind of 'set game' (a simple card game).
And I'm trying to implement .contains methods to find if an array contains a particular case but I'm stuck - in line 67 (if case Card.Symbol.oval = element) I get this error: Enum case 'oval' is not a member of type 'Card'
What am I doing wrong?
import Foundation
struct Deck {
private (set) var cards = [Card] ()
init() {
for symbol in Card.Symbol.all {
cards.append(Card(symbol: symbol))
}
}
}
struct Card: Hashable {
static func == (lhs: Card, rhs: Card) -> Bool {
return lhs.identifier == rhs.identifier
}
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
var symbol: Symbol
enum Symbol: String {
case squiggle = "■"
case oval = "●"
case diamond = "▲"
static var all = [Symbol.squiggle, .oval, .diamond]
}
private var identifier: Int
private static var identifierFactory = 0
private static func getUniqueIdentifier() -> Int {
identifierFactory += 1
return identifierFactory
}
init(symbol: Symbol) {
self.identifier = Card.getUniqueIdentifier()
self.symbol = symbol
}
}
struct SetGame {
var deck = Deck ()
lazy var cardsInDeck = deck.cards
var cardsOpen = [Card] ()
var cardsChosen = [Card] ()
mutating func chooseCard(at index: Int) {
if cardsChosen.count < 3 {
cardsChosen.append(cardsOpen[index])
}
let itemFound = cardsChosen.contains { element in
if case Card.Symbol.oval = element {
return true
} else {
return false
}
}
}
}

Related

Does swift type inference not work with function return types?

Does swift type inference not work with function return types?
protocol Vehicle {
func numberOfWheels() -> Int
}
struct Car: Vehicle {
func numberOfWheels() -> Int {
return 4
}
}
struct Bike: Vehicle {
func numberOfWheels() -> Int {
return 2
}
}
struct Truck: Vehicle {
func numberOfWheels() -> Int {
return 8
}
}
struct VehicleFactory {
static func getVehicle<T: Vehicle>(_ vehicleType: T.Type = T.self) -> T? {
let id = identifier(for: T.self)
switch id {
case "Car":
return Car() as? T
case "Bike":
return Bike() as? T
default:
return nil
}
}
private static func identifier(for type: Any.Type) -> String {
String(describing: type)
}
}
let v: Bike = VehicleFactory.getVehicle() // ERROR HERE: Cannot convert value of type 'T?' to specified type 'Bike'
print(v.numberOfWheels())
I am trying this in playground. Why is there an error in above line?
Shouldnt the compiler infer the type to be Bike from the let v: Bike declaration?
The problem is that getVehicle returns an optional, you have to declare
let v: Bike? = VehicleFactory.getVehicle()
Further you have to unwrap v in the print line
Not a direct answer to your question. Vadian has already answered but a few notes on your implementation:
(_ vehicleType: T.Type = T.self) is pointless. You can just omit it.
Second I would simply add init() to your protocol requirements, get rid of the identifier method, change number of wheels to a computed property:
protocol Vehicle {
init()
var numberOfWheels: Int { get }
}
struct Car: Vehicle {
let numberOfWheels = 4
}
struct Bike: Vehicle {
let numberOfWheels = 2
}
struct Truck: Vehicle {
let numberOfWheels = 8
}
struct VehicleFactory {
static func getVehicle<T: Vehicle>() -> T { .init() }
}
let v: Bike = VehicleFactory.getVehicle()
print(v.numberOfWheels) // "2\n"

Swift - What is the difference between implementing Hashable and Equatable and NSObject hash and isEqual overrides

I'm trying to wrap my head around the new DiffableDataSource way of handling data in tableviews/collectionviews and during testing I came across a strange crash.
I would expect that the two implementations below would work exactly the same:
Implementation 1:
class DiffableSection {
var id: String
var items: [AnyDiffable]
init(id: String,
items: [AnyDiffable] = []) {
self.id = id
self.items = items
}
}
extension DiffableSection: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
extension DiffableSection: Equatable {
static func == (lhs: DiffableSection, rhs: DiffableSection) -> Bool {
return lhs.id == rhs.id
}
}
Implementation 2:
class DiffableSection: NSObject {
var id: String
var items: [AnyDiffable]
init(id: String,
items: [AnyDiffable] = []) {
self.id = id
self.items = items
}
// MARK: - Hashable and Equatable
public override var hash: Int {
var hasher = Hasher()
hasher.combine(id)
return hasher.finalize()
}
public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? DiffableSection else { return false }
return id == object.id
}
}
but apparently they are not - Implementation 2 works with the code below and Implementation 1 does not.
func apply(_ sections: [DiffableSection]) {
var snapshot = self.snapshot()
for section in sections {
snapshot.appendSectionIfNeeded(section)
snapshot.appendItems(section.items, toSection: section)
}
apply(snapshot)
}
(...)
extension NSDiffableDataSourceSnapshot {
mutating func appendSectionIfNeeded(_ identifier: SectionIdentifierType) {
if sectionIdentifiers.contains(identifier) { return }
appendSections([identifier])
}
}
The crash message I get when running with Implementation 1:
'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: section != NSNotFound'
Can someone explain me what are the differences in those implementations? How could I fix Implementation 1 to work same as Implementation 2??

Swift - How to populate array

I want to send a post request to my API but I am having some issues with mapping.
The user starts on VCA and sees a list of users that is retrieved via GET request, the user can tap on a cell and see the details (VCB). on VCB, you can tap a cell again, and you get an action sheet which will update that status to available or unavailable. The issue I have is to populate the dailyInjuryStatus array in the POST request.
Get request model:
struct DailyInjuryIllnessPlayer: Hashable, Codable {
var playerId: Int
var playerName: String?
var numberOfStatusMissingDays: Int
var entries: [Entry]
func hash(into hasher: inout Hasher) {
hasher.combine(playerId)
}
static func == (lhs: DailyInjuryIllnessPlayer, rhs: DailyInjuryIllnessPlayer) -> Bool {
return lhs.playerId == rhs.playerId
}
}
struct Entry: Codable {
var injuryIllnessId: Int
var injuryIllnessName: String?
var statusDate: Date
var modifiedBy: String?
var status: String?
var playerStatusId: Int
var parentEventId: Int?
}
The model for the POST
struct CreateDailyInjuryIllnessNote: Encodable {
var teamId: UInt32
var dailyInjuryIllnessStatus: [DailyInjuryIllnessStatus]
}
struct DailyInjuryIllnessStatus: Encodable {
var iIeventId: UInt32
var effectiveDate: Date
var eventStatusId: UInt32
var playerId: UInt32
}
The code I am using for the request (Extracting the values from the screen to send to the API):
private extension DailyInjuryIllnessAPI.Model.Request.CreateDailyInjuryIllnessNote {
static func from(playerId: Int?, statusNote: DailyInjuryIllnessPlayer) -> Self? {
guard let playerId = playerId else { return nil }
let teamId = getTeamId(from: statusNote)
// Here is the issue, I can populate teamId, but I cannot populate dailyInjuryIllnessStatus.
return .init(teamId: UInt32(teamId), dailyInjuryIllnessStatus: <#T##[DailyInjuryIllnessAPI.Model.Request.DailyInjuryIllnessStatus]#>)
}
private static func getTeamId(from model: DailyInjuryIllnessPlayer) -> Int {
let answer = model.playerId
return answer
}
private static func getEventId(from model: DailyInjuryIllnessPlayer) -> Int {
var answer = 1
for eventId in model.entries {
answer = eventId.injuryIllnessId
}
return answer
}
private static func getEffectiveDate(from model: DailyInjuryIllnessPlayer) -> Date {
var answer = Date()
for date in model.entries {
answer = date.statusDate
}
return answer
}
private static func getEventStatusId(from model: DailyInjuryIllnessPlayer) -> Int {
var answer = 1
for statusId in model.entries {
answer = statusId.playerStatusId
}
return answer
}
private static func getPlayerId(from model: DailyInjuryIllnessPlayer) -> Int {
var answer = model.playerId
return answer
}
}
The issue as stated in the code is at the return .init Swift expects it to be like the model which has a teamId and an array of DailyInjuryIllnessStatus. How can I put the methods I used to extract those values into the array

Infer return type from function using switch control flow

I've got a set of properties/protocols (back story is here, but I think it's superfluous)
The class types look like this:
struct AdjustmentTypes {
internal class BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
class FloatType: BaseType<CGFloat> { }
class IntType: BaseType<Int> { }
}
And I'm using type erasure to remove the type so I can store these in a Set, and I've built some helper methods to make my Set tooling simpler:
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert(_ adjustment: AnyHashable) {
adjustmentsSet.insert(adjustment)
}
func remove(_ adjustment: AnyHashable) {
adjustmentsSet.remove(adjustment)
}
func contains(_ adjustment: AnyHashable) -> Bool {
return adjustmentsSet.contains(adjustment)
}
var count: Int { return adjustmentsSet.count }
}
var adjustmentsSet = AdjustmentsSet()
What I want to do now is add some helpers to my Set management class to be able to retrieve a property with the correct type, e.g. if I do:
let brightness = Brightness().make()
adjustments.get(brightness)
It should return nil, but if I do:
adjustments.insert(brightness)
adjustments.get(brightness)
I should now get the value back, as its correct type, AdjustmentTypes.FloatType.
I'm thinking to so something with a Switch statement like this:
class AdjustmentsSet {
// ...
func get(_ adjustment: AnyHashable) -> Any? {
guard let untyped = adjustmentsSet.first(where: { $0 == adjustment }) else { return nil }
switch adjustment {
case _ as AdjustmentTypes.FloatType: return untyped as! AdjustmentTypes.FloatType
case _ as AdjustmentTypes.IntType: return untyped as! AdjustmentTypes.IntType
default: return nil
}
}
}
However, the fatal flaw of course, is that this returns Any, instead of the intended type.
How can I infer the return value's type and to return the correct type?
Complete example, just drop this into a playground:
// Generic conforming protocol to AnyHashable
protocol AnyAdjustmentProtocol {
func make() -> AnyHashable
}
protocol AdjustmentProtocol: AnyAdjustmentProtocol {
associatedtype A
func make() -> A
}
struct AdjustmentTypes {
internal class BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
class FloatType: BaseType<CGFloat> { }
class IntType: BaseType<Int> { }
}
struct AnyAdjustmentType<A>: AdjustmentProtocol, Hashable {
static func == (lhs: AnyAdjustmentType<A>, rhs: AnyAdjustmentType<A>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
private let _make: () -> AnyHashable
private let hashClosure:() -> Int
var hashValue: Int {
return hashClosure()
}
init<T: AdjustmentProtocol & Hashable>(_ adjustment: T) where T.A == A {
_make = adjustment.make
hashClosure = { return adjustment.hashValue }
}
func make() -> AnyHashable {
return _make()
}
}
struct Brightness: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
}
}
struct WhiteBalance: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
}
let brightness = Brightness().make()
let whiteBalance = WhiteBalance().make()
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert(_ adjustment: AnyHashable) {
adjustmentsSet.insert(adjustment)
}
func remove(_ adjustment: AnyHashable) {
adjustmentsSet.remove(adjustment)
}
func contains(_ adjustment: AnyHashable) -> Bool {
return adjustmentsSet.contains(adjustment)
}
var count: Int { return adjustmentsSet.count }
}
var adjustmentsSet = AdjustmentsSet()
You need to rewrite the method as a generic and call it with sufficient type information, i.e. you need to know in advance what type you expect the method to return.
I'm also not sure passing around AnyHashables is ideal anyway. Nothing stops you from adding Strings, Ints and other random types that are hashable to your adjustment set.
var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert("1") // compiles just fine!
Alternatively, you could use and pass around your AdjustmentTypes and rewrite the AdjustmentsSet class with generic methods:
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.insert(adjustment)
}
func remove<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.remove(adjustment)
}
func contains<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> Bool {
return adjustmentsSet.contains(adjustment)
}
func get<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> AdjustmentTypes.BaseType<T>? {
return (adjustmentsSet.compactMap { $0 as? AdjustmentTypes.BaseType<T> }).first(where: { $0 == adjustment })
}
var count: Int { return adjustmentsSet.count }
}
Next, your make() methods should be more strongly typed as well, since you are not passing around AnyHashables. I implemented brightness and white balance like this:
extension AdjustmentTypes {
static let Brightness = AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
static let WhiteBalance = AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
And also took advantage of type aliases and structs in Swift, to make your adjustment type system behave with value semantics:
struct AdjustmentTypes {
struct BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
typealias FloatType = BaseType<CGFloat>
typealias IntType = BaseType<Int>
}
Finally, you are able to use the adjustment set as intended:
var brightness = AdjustmentTypes.Brightness
brightness.value = 0.5
var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert(brightness)
let retrievedBrightness = adjustmentsSet.get(AdjustmentTypes.Brightness)! // strongly typed!
retrievedBrightness.value // 0.5
AdjustmentTypes.Brightness.value // 0.0
The entire playground:
struct AdjustmentTypes {
struct BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
typealias FloatType = BaseType<CGFloat>
typealias IntType = BaseType<Int>
}
extension AdjustmentTypes {
static let Brightness = AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
static let WhiteBalance = AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
class AdjustmentsSet {
private var adjustmentsSet: Set<AnyHashable> = []
func insert<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.insert(adjustment)
}
func remove<T>(_ adjustment: AdjustmentTypes.BaseType<T>) {
adjustmentsSet.remove(adjustment)
}
func contains<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> Bool {
return adjustmentsSet.contains(adjustment)
}
func get<T>(_ adjustment: AdjustmentTypes.BaseType<T>) -> AdjustmentTypes.BaseType<T>? {
return (adjustmentsSet.compactMap { $0 as? AdjustmentTypes.BaseType<T> }).first(where: { $0 == adjustment })
}
var count: Int { return adjustmentsSet.count }
}
var brightness = AdjustmentTypes.Brightness
brightness.value = 0.5
var adjustmentsSet = AdjustmentsSet()
adjustmentsSet.insert(brightness)
let retrievedBrightness = adjustmentsSet.get(AdjustmentTypes.Brightness)! // strongly typed!
retrievedBrightness.value // 0.5
AdjustmentTypes.Brightness.value // 0.0
Hope this helps, good luck with your project!

Storing objects conforming to a protocol with generics in a typed array

I've got a protocol:
protocol Adjustable: Equatable {
associatedtype T
var id: String { get set }
var value: T { get set }
init(id: String, value: T)
}
And a struct that conforms to it:
struct Adjustment: Adjustable {
static func == (lhs: Adjustment, rhs: Adjustment) -> Bool {
return lhs.id == rhs.id
}
typealias T = CGFloat
var id: String
var value: T
}
And I'm building a wrapper class that behaves like a Set to handle an ordered list of these properties:
struct AdjustmentSet {
var adjustmentSet: [Adjustable] = []
func contains<T: Adjustable>(_ item: T) -> Bool {
return adjustmentSet.filter({ $0.id == item.id }).first != nil
}
}
let brightness = Adjustment(id: "Brightness", value: 0)
let set = AdjustmentSet()
print(set.contains(brightness))
But that of course doesn't work, erroring with:
error: protocol 'Adjustable' can only be used as a generic constraint because it has Self or associated type requirements
var adjustmentSet: [Adjustable] = []
Looking around, I thought at first this was because the protocol doesn't conform to Equatable, but then I added it, and it still doesn't work (or I did it wrong).
Moreover, I would like to be able to use a generic here, so that I can do something like:
struct Adjustment<T>: Adjustable {
static func == (lhs: Adjustment, rhs: Adjustment) -> Bool {
return lhs.id == rhs.id
}
var id: String
var value: T
}
let brightness = Adjustment<CGFloat>(id: "Brightness", value: 0)
Or:
struct FloatAdjustment: Adjustable {
static func == (lhs: Adjustment, rhs: Adjustment) -> Bool {
return lhs.id == rhs.id
}
typealias T = CGFloat
var id: String
var value: T
}
let brightness = FloatAdjustment(id: "Brightness", value: 0)
And still be able to store an array of [Adjustable] types, so that eventually I can do:
var set = AdjustmentSet()
if set.contains(.brightness) {
// Do something!
}
Or
var brightness = ...
brightness.value = 1.5
set.append(.brightness)
You can't have an array of items of type Adjustable, because Adjustable isn't really a type. It's a blue print that describes a set of types, one per every possible value of T.
To get around this, you need to use a type eraser https://medium.com/dunnhumby-data-science-engineering/swift-associated-type-design-patterns-6c56c5b0a73a
Have made some great progress using Alexander's suggestion; I was able to use some nested class types to inherit the base type erasure class, and use a generic protocol that conforms to AnyHashable so I can use this with a set!
// Generic conforming protocol to AnyHashable
protocol AnyAdjustmentProtocol {
func make() -> AnyHashable
}
protocol AdjustmentProtocol: AnyAdjustmentProtocol {
associatedtype A
func make() -> A
}
struct AdjustmentTypes {
internal class BaseType<T>: Hashable {
static func == (lhs: AdjustmentTypes.BaseType<T>, rhs: AdjustmentTypes.BaseType<T>) -> Bool {
return lhs.name == rhs.name
}
typealias A = T
var hashValue: Int { return name.hashValue }
let name: String
let defaultValue: T
let min: T
let max: T
var value: T
init(name: String, defaultValue: T, min: T, max: T) {
self.name = name
self.defaultValue = defaultValue
self.min = min
self.max = max
self.value = defaultValue
}
}
class FloatType: BaseType<CGFloat> { }
class IntType: BaseType<Int> { }
}
struct AnyAdjustmentType<A>: AdjustmentProtocol, Hashable {
static func == (lhs: AnyAdjustmentType<A>, rhs: AnyAdjustmentType<A>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
private let _make: () -> AnyHashable
private let hashClosure:() -> Int
var hashValue: Int {
return hashClosure()
}
init<T: AdjustmentProtocol & Hashable>(_ adjustment: T) where T.A == A {
_make = adjustment.make
hashClosure = { return adjustment.hashValue }
}
func make() -> AnyHashable {
return _make()
}
}
struct Brightness: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.FloatType(name: "Brightness", defaultValue: 0, min: 0, max: 1)
}
}
struct WhiteBalance: AdjustmentProtocol, Hashable {
func make() -> AnyHashable {
return AdjustmentTypes.IntType(name: "White Balance", defaultValue: 4000, min: 3000, max: 7000)
}
}
let brightness = Brightness().make()
let whiteBalance = WhiteBalance().make()
var orderedSet = Set<AnyHashable>()
orderedSet.insert(brightness)
print(type(of: orderedSet))
print(orderedSet.contains(brightness))
for obj in orderedSet {
if let o = obj as? AdjustmentTypes.FloatType {
print(o.value)
}
if let o = obj as? AdjustmentTypes.IntType {
print(o.value)
}
}
Prints:
Set<AnyHashable>
true
0.0
Special thanks to this article: https://medium.com/#chris_dus/type-erasure-in-swift-84480c807534 which had a simple and clean example on how to implement a generic type eraser.
With Swift 5.7 you will be able to this without any error from the compiler by prefixing your protocol with any, so your set becomes:
struct AdjustmentSet {
var adjustmentSet: [any Adjustable] = []
func contains(_ item: some Adjustable) -> Bool {
return adjustmentSet.first { $0.id == item.id } != nil
}
}
Note that all items in your adjustmentSet array will be allocated on heap since compile time swift can't determine the size of existential type Adjustable as types implementing it will have variable size.

Resources