How to use generics as params?(Swift 2.0) - ios

Code in playground is here
class ProductModel {
var productID : Int = 0
init(id:Int) {
productID = id
}
}
protocol GenericListProtocol {
typealias T = ProductModel
var list : [T] { get set }
var filteredlist : [T] { get set }
func setData(list : [T])
}
extension GenericListProtocol {
func setData(list: [T]) {
list.forEach { item in
guard let productItem = item as? ProductModel else {
return
}
print(productItem.productID)
}
}
}
class testProtocol {
class func myfunc<N:GenericListProtocol>(re:N){
var list : [ProductModel] = [ProductModel(id: 1),ProductModel(id: 2),ProductModel(id: 3),ProductModel(id: 4)]
re.setData(list)
}
}
But in the line re.setData(list)
get compile error:
Cannot convert value of type '[ProductModel]' to expected argument
type '[_]'.
My Question is How to use setData method in GenericListProtocol?
Anyone could help will be appreciated.

Moving the ProductModel type into the extension and removing the constraint from the generic protocol seems to work.
class ProductModel {
var productID : Int = 0
init(id:Int) {
productID = id
}
}
protocol GenericListProtocol {
typealias T
var list : [T] { get set }
var filteredlist : [T] { get set }
func setData(list : [T])
}
extension GenericListProtocol {
func setData(list: [ProductModel]) {
list.forEach { item in
print(item.productID)
}
}
}
class testProtocol {
class func myfunc<N:GenericListProtocol>(re:N) {
let list : [ProductModel] = [ProductModel(id: 1),ProductModel(id: 2),ProductModel(id: 3),ProductModel(id: 4)]
re.setData(list)
}
}

I found this question interesting and thought how best we could solve it in generic way.
protocol Product {
var productID : Int {get set}
}
class ProductModel: Product {
var productID : Int = 0
init(id:Int) {
productID = id
}
}
protocol GenericListProtocol {
typealias T : Product
var list : [T] { get set }
var filteredlist : [T] { get set }
}
extension GenericListProtocol {
func setData(list: [T]) {
list.forEach { item in
print(item.productID)
}
}
}
class GenericListProtocolClass : GenericListProtocol
{
typealias T = ProductModel
var intVal = 0
var list = [T]()
var filteredlist = [T]()
}
class testProtocol {
class func myfunc(re: GenericListProtocolClass){
let list : [ProductModel] = [ProductModel(id: 1),ProductModel(id: 2),ProductModel(id: 3),ProductModel(id: 4)]
re.setData(list)
}
}
let temp = GenericListProtocolClass()
testProtocol.myfunc(temp)
Appreciate your thought and suggestion if it can be improved further.

Related

is it possible to use Generic dynamic in Swift

protocol Base {
associatedtype M
var data:M { get set }
func update(data:M)
}
class ViewA : Base {
var data: String = ""
func update(data: String) {}
}
class ViewB : Base {
var data: Int = 2
func update(data: Int) {}
}
var dataArr : [Any] = ["1",2]
var viewArr : [Any] = [ViewA(), ViewB()]
func updatData() {
func update<C, T>(view:C, data:T) where C : Base, C.M == T {
view.update(data: data)
}
for i in 0..<2 {
let view = viewArr[i]
let data = dataArr[I]
// ! there is a errr here, Protocol 'Any' as a type cannot conform to 'Base'
update(view: view, data: data)
}
}
My Views conform to this 'Base' protocol which define what type of data my view use
And I want to implement this updatData function dynamic tell if data can be send to view (base on viwe.m type is same to data's type)
But it is seems to be impossible in Swift?
Array of Any object pass as Base Protocol create conflict.
so add one more class for Base class of ViewA and ViewB
protocol Base {
associatedtype M
var data: M { get set }
func update(data: M)
}
class Base1: Base {
typealias M = Any
var data: Any = ""
func update(data: Any) {
print("Udate \(data)")
}
}
class ViewA: Base1 {
//typealias M = String
//var data: String = ""
override func update(data: Any) {
print("test")
}
}
class ViewB: Base1 {
//typealias M = Int
//var data: Int = 2
override func update(data: Any) {
print(data)
print("Udate")
}
}
var dataArr: [Any] = ["1", 2]
var viewArr: [Any] = [ViewA(), ViewB()]
func updatData() {
func update<C, T>(view: C, data: T) where C: Base, C.M == T {
view.update(data: data)
}
for i in 0..<2 {
let view = viewArr[i]
let data = dataArr[i]
update(view: view as! Base1, data: data)
}
}
You want to create a type erased Base concrete type here: AnyBase:
public final class AnyBase: Base {
fileprivate let _boxed: _Box<M>
public init<Concrete: Base>(_ concrete: Concrete) where Concrete.M == M {
self._boxed = _ConcreteBox(concrete)
}
// Base conformance
public var data: M { _boxed.data }
public func update(data: M) {
_boxed.update(data: data)
}
// Type erasure
fileprivate class _Box<T>: Base {
init() {
guard type(of: self) != _Box.self else { fatalError("Can't create _Box instances, create a sub class instance instead ") }
}
// Base conformance
var base: M {
get { fatalError("Must override") }
set { fatalError("Must override") }
}
func update(data: M) {
fatalError("Must override")
}
}
fileprivate final class _ConcreteBox<Concrete: Base>: _Box<Concrete.M> where M == Concrete.M {
let _concrete: Concrete
init(_ concrete: Concrete) {
self._concrete = concrete
super.init()
}
// Base conformance
override var data: {
get { _concrete.data }
set { _concrete.data = newValue }
}
override func update(data: M) {
_concrete.update(data: data)
}
}
}
Now you can store different concrete instances of Base<M> in an array by adopting the type erased AnyBase<M> instead of using Any in your arrays.

Replacing Element in a Set if a condition is met

I'm working with a Set of CarCagetory:
public struct Images {
static let categoryTeaser = UIImage()
}
public enum PremiumModel {
case model1, model2, model3, unknown
}
public struct CarCategory {
public let teaserImage: UIImage
public let make: String
public let model: PremiumModel
public let startPrice: Double
}
// MARK: - Equatable
extension CarCategory: Equatable {
public static func == (lhs: CarCategory, rhs: CarCategory) -> Bool {
return lhs.model == rhs.model
}
}
// MARK: - Hashable
extension CarCategory: Hashable {
public var hashValue: Int {
return model.hashValue
}
}
I'm iterating over an array of Cars and extracting a Set of categories according to the model:
var categories = Set<CarCategory>()
carSpecifications.forEach {
if PremiumModel(rawValue: $0.car.model) != .unknown {
categories.insert(CarCategory(teaserImage: Images.categoryTeaser, make: $0.car.make, model: PremiumModel(rawValue: $0.car.model), startPrice: $0.pricing.price))
}
}
This works just fine.
Now I want to keep my Set updated with the lowest price for a certain model. I'm thinking on a dictionary of [PremiumModel: Double] where I keep the lowest price for a model and at the end I update my Set accordingly, but I wonder if there is a better way.
Edit:
That's my current implementation using a dictionary. It feels rudimentary...
carSpecifications.forEach {
let model = PremiumModel(rawValue: $0.car.model)
if model != .unknown {
if let value = minPriceForModel[model] {
minPriceForModel[model] = min(value, $0.pricing.price)
} else {
minPriceForModel[model] = $0.pricing.price
}
categories.insert(CarCategory(teaserImage: Images.categoryTeaser, make: $0.car.make, model: model, startPrice: $0.pricing.price))
}
}
let sortedCategories = Array(categories.sorted(by: <))
.compactMap { (category: CarCategory) -> CarCategory in
var newCategory = category
newCategory.startPrice = minPriceForModel[category.model] ?? 0
return newCategory
}
return sortedCategories

Swift 2 Correct way to get level of any object game, protocol? struct? extension?

This is my first game, and I'm new on swift and sprite kit.
I must have a level for each class that needs get level. Like car lev1 car lev 2 etc. I have read about protocol extension etc, witch is the best way to approach level management?
I have tried to use LevelTraker as extension of this protocol:
protocol LevelTracker {
typealias TypeUnit: TypeGame
var nameClass: String! {get set}
var currentLevel : Int {get set}
mutating func levelIncreases()
}
but with extension, i must write 3 var each class that needs level.
i try the same extension LevelTraker with struct LevelTraker:
func getClassName (theClass:AnyObject) -> String {
let name = _stdlib_getDemangledTypeName(theClass); return name}
protocol TypeGame {}
enum transportType : TypeGame {
case ground, sea, air
}
struct LevelTracker {
var sender: AnyObject
var TypeUnit: TypeGame
private func getSaveFileWhitName() -> String {
let saveWithName = getClassName(sender) + "." + String(TypeUnit)
return saveWithName
}
var currentLevel : Int {
get {
let stringName = getSaveFileWhitName()
let returnValue : Int = dataBase.read(stringName) as? Int ?? 1 //Check for first run of app, if = nil, set = 1
return returnValue
}
set (newValue) {
let stringName = getSaveFileWhitName()
let level : Int = self.currentLevel
let val = newValue
if (newValue > level) {dataBase.write(val, key: stringName)}
}
}
mutating func levelIncreases() {self.currentLevel++}
///SERVE SOLO PER SVILUPPO
mutating func RESETLEVEL() {dataBase.write(1, key: getSaveFileWhitName())}
}
To use: (thanks #Krzak)
class car {
init () {
let level = LevelTracker(sender: self, TypeUnit: transportType.ground).currentLevel
}
}
But I don't want modify all init object that use level, and the super super class in common, some class don't have propriety level.
The reason why you have compiler error is in your last line. You're missing the .ground
I'm not sure how you're thinking though that this will work, shouldn't it be var?
var level = LevelTracker(sender: self, TypeUnit: transportType.ground).currentLevel
What I am reading it sounds like you are doing this:
class Level : AnyObject
{
private func getSaveFileWhitName() -> String {
let saveWithName = getClassName(sender) + "." + String(TypeUnit)
return saveWithName
}
var currentLevel : Int {
get {
let stringName = getSaveFileWhitName()
let returnValue : Int = dataBase.read(stringName) as? Int ?? 1 //Check for first run of app, if = nil, set = 1
return returnValue
}
set (newValue) {
let stringName = getSaveFileWhitName()
let level : Int = self.currentLevel
let val = newValue
if (newValue > level) {dataBase.write(val, key: stringName)}
}
}
mutating func levelIncreases() {self.currentLevel++}
///SERVE SOLO PER SVILUPPO
mutating func RESETLEVEL() {dataBase.write(1, key: getSaveFileWhitName())}
}
class car : Level
{
init () {
let level = self.currentLevel
}
}
I found a solution, I'm happy to have some comment.
protocol TypeGame {}
enum transportType : TypeGame {
case car, bus, trak
}
protocol LevelTracker {
var nameClass: String! {get}
var currentLevel : Int {get set}
mutating func levelIncreases()
}
extension LevelTracker {
var currentLevel : Int {
get {/*set to DB*/ return 1}
set (newValue) {/*set to DB*/}
}
mutating func levelIncreases() {self.currentLevel++}}
A protocol only for transport object:
protocol Transport : LevelTracker {}
Ok, now my (simplified) class are:
class AllNode {//SKSpriteNode
init(){}
}
class TransportGame:AllNode, Transport {
var nameClass : String! = "Transport"
override init() {
super.init()
self.nameClass = nameClass + "." + getClassName(self)}
}
class Car : TransportGame {}
class miniCar : Car {}
class Bus: TransportGame {}
class Tree: AllNode {}
var carOne = Car()
let levelCar = carOne.currentLevel
var busOne = Bus()
let levelBue = busOne.currentLevel
var treeOne = Tree()
tree.currentLevel //ERROR YUPPI!!!! :)
Now the tree class can't access to level!
What do you think about this solution?

Declare class type of variable in seperate class [Swift]

Here I have a class, Player, that has a variable of type, Sport, of which can be Basketball or Soccer. I'd like to be able to declare the type of Sport in the Player declaration. Any suggestions?
class Soccer : Sport {
override var players : Int { get { return 11 } }
}
class Basketball : Sport {
override var players : Int { get { return 5 } }
}
class Sport {
var teamName: String
var players: Int { get { return 0 } }
init(teamName: String) {
self.teamName = teamName
}
}
class Player {
let sport : Sport?
init? (typeOfSport: Soccer, teamName: String) {
self.sport = Soccer(teamName: teamName)
}
init? (typeOfSport: Basketball, teamName: String) {
self.sport = Basketball(teamName: teamName)
}
}
let me = Player(typeOfSport: Soccer(), teamName: "chelsea")
let him = Player(typeOfSport: Basketball(), teamName: "wizards")
You could also use an enum for this like this:
enum Sport {
case Soccer (teamName : String)
var players: Int {
switch self{
case .Soccer: return 11
default: return 0
}
}
}
class Player {
let sport: Sport?
init? (s : Sport){
self.sport = s
}
}
Sport.Soccer (teamName: "Cambuur").players
In this case I suggest for your example is this solution, I don't know if is the better way, but in my studies about OOP, I believe it is a cool way to do your example.
protocol Sport {
func getTotalPlayers() -> Int
}
class Soccer: Sport {
func getTotalPlayers() -> Int {
return 11
}
}
class Basketball: Sport {
func getTotalPlayers() -> Int {
return 5
}
}
class Team {
private var sport: Sport
private var name: String
init(sport:Sport, name:String) {
self.sport = sport
self.name = name
}
func getTeamName() -> String {
return name
}
func getSport() -> Sport {
return sport
}
}
class Chelsea: Team {
init() {
super.init(sport: Soccer(), name: "Chelsea")
}
}
class Wizards: Team {
init() {
super.init(sport: Basketball(), name: "Wizards")
}
}
class Player {
private var team: Team
init(team: Team) {
self.team = team
}
func getTeamName() -> String {
return self.team.getTeamName()
}
func getSport() -> Sport {
return self.team.getSport()
}
}
let me = Player(team: Chelsea())
let him = Player(team: Wizards())
I found a way to do this.. If you declare the typeOfSport in the player initialization function Sport.Type and then make the Sport initialization method required like so....
class Soccer : Sport {
override var players : Int { get { return 11 } }
}
class Basketball : Sport {
override var players : Int { get { return 5 } }
}
class Sport {
var teamName: String
var players: Int { get { return 0 } }
required init(teamName: String) {
self.teamName = teamName
}
}
class Player {
let sport : Sport?
init? (typeOfSport: Sport.Type, teamName: String) {
self.sport = Soccer(teamName: teamName)
}
init? (typeOfSport: Basketball, teamName: String) {
self.sport = Basketball(teamName: teamName)
}
}
let me = Player(typeOfSport: Soccer.self, teamName: "chelsea")
let him = Player(typeOfSport: Basketball.self, teamName: "wizards")

Swift generic function parameter as Class

I'm not sure that this not duplicate. I have protocol and several classs that confurm to it.
protocol DbObject: class {
class func tableName() -> String
init(set: FMResultSet)
func save(db: FMDatabase)
}
And here how I use it:
func updateTable<T where T:DbObject>(nodes: [T]) {
self.db.executeUpdate("DELETE from \(T.tableName())")
for elem in nodes {
elem.save(self.db)
}
}
func loadAllFromObjectTable<T where T:DbObject>(cl: T) -> [T] {
var objArr = [T]()
if let set = db.executeQuery("select * from \(T.tableName())") {
while (set.next() ?? false) {
let obj = T(set: set)
objArr.append(obj)
}
}
return objArr
}
But I wanna that function loadAllFromObjectTable get as parameter class that confirms protocol, not object. How can I achieve that?
EDIT:
From here https://stackoverflow.com/a/26229630/820795
func loadAllFromObjectTable<T where T:DbObject>(_: T.Type) -> [T] {
var objArr = [T]()
if let set = db.executeQuery("select from \(T.tableName())") {
while (set.next() ?? false) {
if let obj = T(set: set)
objArr.append(obj)
}
}
return objArr
}
And usage:
manager.loadAllFromObjectTable(SignNote.self)

Resources