So I'm learning how to make my Android apps into an iOS app. I've gotten pretty far though I'm having an issue when it comes creating the object. In my android app I read in a csv file and create a FireworkList object that contains info. Here is the code from my Android app:
import java.util.ArrayList;
public class FireworksList{
private ArrayList<Integer> _category = new ArrayList<>();
private ArrayList<String> _name = new ArrayList<>();
private ArrayList<String> _shotCount = new ArrayList<>();
private ArrayList<String> _price = new ArrayList<>();
private ArrayList<String> _description = new ArrayList<>();
private ArrayList<String> _videoUrl = new ArrayList<>();
private ArrayList<Integer> _imageResourceNumber = new ArrayList<>();
private ArrayList<Boolean> _favorite = new ArrayList<>();
private ArrayList<Boolean> _special = new ArrayList<>();
private Integer _specialCategoryNumer =15;
private Integer _nextId;
public FireworksList() {
_nextId=0;
}
public ArrayList<Integer> get_category() {
return _category;
}
public ArrayList<String> get_name() {
return _name;
}
public ArrayList<String> get_shotCount() {
return _shotCount;
}
public ArrayList<String> get_price() {
return _price;
}
public ArrayList<String> get_description() {
return _description;
}
public ArrayList<String> get_videoUrl() {
return _videoUrl;
}
public ArrayList<Integer> get_imageResourceNumber() {
return _imageResourceNumber;
}
public ArrayList<Boolean> get_favorite() {
return _favorite;
}
public void set_favorite(int index, Boolean bool) {
_favorite.set(index,bool);
}
public ArrayList<Boolean> get_special(){return _special;}
public void Add(int cat, String name, String shot, String price, String description, String video, int image, Boolean fav, Boolean special){
_category.add(_nextId,cat);
_name.add(_nextId,name);
_shotCount.add(_nextId,shot);
_price.add(_nextId,price);
_description.add(_nextId,description);
_videoUrl.add(_nextId,video);
_imageResourceNumber.add(_nextId,image);
_favorite.add(_nextId,fav);
_special.add(_nextId,special);
_nextId++;
}
public int Count(){
return _nextId;
}
public FireworksList CategorySort(int position){
FireworksList fireworksListTemp = new FireworksList();
for(int i=0; i<_nextId;i++){
if(position==0){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
else if(position==_category.get(i)){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
else if(position==_specialCategoryNumer&&_special.get(i)==true){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
}
return fireworksListTemp;
}
public FireworksList FavoriteSort(){
FireworksList fireworksListTemp = new FireworksList();
for(int i = 0; i<_nextId;i++){
if(_favorite.get(i)==true){
fireworksListTemp.Add(_category.get(i),_name.get(i),_shotCount.get(i),_price.get(i),_description.get(i),_videoUrl.get(i),_imageResourceNumber.get(i),_favorite.get(i),_special.get(i));
}
}
return fireworksListTemp;
}
public int FindIndex(String name, FireworksList fireworksList){
int found=0;
for(int j=0;j<fireworksList.Count();j++){
if(fireworksList.get_name().get(j).equals(name)){
found=j;
}
}
return found;
}
}
I've started rewriting my code yet I ran into an issue when it came to creating a new Firework list then appending to it with what is needed in the categorySort function. Here is my modified code so far:
class FireworkList {
var _category = [Int]()
var _name = [String]()
var _shotCount = [String]()
var _price = [String]()
var _description = [String]()
var _videioUrl = [String]()
var _imageResourceNumber = [Int]()
var _favorite = [Bool]()
var _special = [Bool]()
private var _specialCategoryNumber : Int = 15
private var _nextId : Int = 0
func FireworksList(){_nextId = 0}
func get_category() -> Array<Int>{return _category}
func get_name() -> Array<String>{return _name}
func get_shotCount() -> Array<String>{return _shotCount}
func get_price() -> Array<String>{return _price}
func get_discription() -> Array<String>{return _description}
func get_videoUrl() -> Array<String>{return _videioUrl}
func get_imageResourceNumber() -> Array<Int>{return _imageResourceNumber}
func get_favorite() -> Array<Bool>{return _favorite}
func get_special() -> Array<Bool>{return _special}
func set_favorite(index : Int, bool : Bool){_favorite[index] = bool}
func add(cat : Int, name : String, shot : String, price : String, description : String, video : String, image : Int, fav : Bool, special : Bool){
_category.insert(cat, at: _nextId)
_name.insert(name, at: _nextId)
_shotCount.insert(shot, at: _nextId)
_price.insert(price, at: _nextId)
_description.insert(description, at: _nextId)
_videioUrl.insert(video, at: _nextId)
_favorite.insert(fav, at: _nextId)
_special.insert(special, at: _nextId)
_nextId+=1
}
func Count()->Int{return _nextId}
func CategorySort(position : Int)-> [FireworkList]{
var fireworkListTemp = [FireworkList]()
for i in 0..._nextId{
if(position == 0){
fireworkListTemp.append(FireworkList())
}
}
return fireworkListTemp
}
}
I'm thankful for any help.
The main issue here is that your java class is poorly designed and you are taking this design with you when writing it in swift. Rather than having a bunch of properties that are collections you should create a struct for those properties and have one array with the struct. (I didn't include all properties to keep the code shorter).
struct Firework {
var category: Int
var name: String
var shotCount: String
var price: String
var special: Bool
}
and then declare it in the main class
class FireworkList {
private var fireworks = [Firework]()
Below is the class with the add, count and categorySort functions to show some examples of how to use this struct. As you can see this means much less code. I also taken the liberty to rename properties and functions to follow recommended swift naming practices.
For the categorySort I have made use of the high order function filter to collect the correct items. If you are going to work with swift I would recommend you learn more about it and the other high order functions like sort, map etc.
Also worth mentioning to someone coming from java is that we don't use get/set methods to the same extent in swift. We most access the property directly like let x = myObject.someValue or myObject.someValue = 10
class FireworkList {
var fireworks = [Firework]()
private let specialCategoryNumber = 15
func add(cat : Int, name : String, shot : String, price : String, special: Bool) {
self.fireworks.append(Firework(category: cat, name: name, shotCount: shot, price: price, special: special))
}
func count() -> Int { return fireworks.count }
func categorySort(position : Int) -> [Firework] {
switch position {
case 0:
return self.fireworks
case specialCategoryNumber:
return self.fireworks.filter { $0.category == specialCategoryNumber && $0.special}
default:
return self.fireworks.filter {$0.category == position}
}
}
}
Here's how I would do it:
public class FireworksList {
private var _category = [Int]()
private var _name = [String]()
private var _shotCount = [String]()
private var _price = [String]()
private var _description = [String]()
private var _videoURL = [String]()
private var _imageResourceNumber = [Int]()
public var favorite = [Bool]()
private var _special = [Bool]()
private let specialCategoryNumber = 15
private var nextId = 0
public var category: [Int] {
get {
return _category
}
}
public var name: [String] {
get {
return _name
}
}
public var shotCount: [String] {
get {
return _shotCount
}
}
public var price: [String] {
get {
return _price
}
}
public var description: [String] {
get {
return _description
}
}
public var videoURL: [String] {
get {
return _videoURL
}
}
public var imageResourceNumber: [Int] {
get {
return _imageResourceNumber
}
}
public var special: [Bool] {
get {
return _special
}
}
public var count: Int {
get {
return nextId
}
}
public func add( cat: Int, name: String, shot: String, price: String, description: String, video: String, image: Int, fav: Bool, special: Bool) {
self._category.append(cat)
self._name.append(name)
self._shotCount.append(shot)
self._price.append(price)
self._description.append(description)
self._videoURL.append(video)
self._imageResourceNumber.append(image)
self.favorite.append(fav)
self._special.append(special)
nextId += 1
}
public func categorySort(at position: Int) -> FireworksList {
let tmp = FireworksList()
for i in 0...nextId {
if position == 0 || position == category[i] ||
(position == specialCategoryNumber && special[i] == true) {
tmp.add(cat: category[i], name: name[i], shot: shotCount[i], price: price[i], description: description[i], video: videoURL[i], image: imageResourceNumber[i], fav: favorite[i], special: special[i])
}
}
return tmp
}
public func favouriteSort() -> FireworksList {
let tmp = FireworksList()
for i in 0...nextId {
if favorite[i] {
tmp.add(cat: category[i], name: name[i], shot: shotCount[i], price: price[i], description: description[i], video: videoURL[i], image: imageResourceNumber[i], fav: favorite[i], special: special[i])
}
}
return tmp
}
// I'm putting this function as static as it isn't directly related to any particular instance of FireworksList at any point of time.
public static func findIndex(name: String, fireworksList: FireworksList) -> Int {
var found = 0
for j in 0...fireworksList.count {
if fireworksList.name[j] == name {
found = j
}
}
return found
}
}
My code simply almost directly follows your Java code.
This is my first time trying to contribute in Stack Overflow, and I hope this can be helpful to you.
Related
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
I have a phone number model which looks like this:
import UIKit
import Foundation
struct PhoneValidation : OptionSet {
let rawValue: Int
static let phoneInValid = PhoneValidation(rawValue: 1 << 0)
static let phoneValid = PhoneValidation(rawValue: 1 << 1)
static let smsValidationAttempted = PhoneValidation(rawValue: 1 << 2)
static let smsValidationFailed = PhoneValidation(rawValue: 1 << 3)
static let smsValidationSuccessful = PhoneValidation(rawValue: 1 << 4) // OTP is successfully validated in backend. The field should be non-editable in this duration
static let smsValidationOTPTriggered = PhoneValidation(rawValue: 1 << 5) // OTP validation triggered. The field should be non-editable in this duration
}
class PhonesViewModel: NSCopying {
public var phoneType: PhoneNumberType = PhoneNumberType.mobile
public var phone: String?
public var code: String?
public var countryCode: String?
public var isValid : PhoneValidation?
func copy(with zone: NSZone? = nil) -> Any {
let copy = PhonesViewModel()
copy.phoneType = phoneType
copy.phone = phone
copy.code = code
copy.countryCode = countryCode
copy.isValid = isValid
return copy
}
}
As you can see above the phone model can transition between different states. The SMS validation is available for few countries and for few it is not applicable. So, I plan on setting smsValidationOTPTriggered state when SMS validation is applicable for a country and while the validation is in progress.
What I need here is, while the states smsValidationOTPTriggered or smsValidationSuccessful are set I would not want any module of the application to modify the values(phoneType, phone, code, countryCode) of the model. In other words, I would like the model to switch to a read-only mode while these 2 states are set in model and would like the module to be informed with an error or exception when a modification is attempted.
Is there a best practice already available for what I am trying to achieve here? I have searched before raising this question but did not find any. How can I achieve this?
Thanks,
Raj Pawan Gumdal
How about something like this, I think its better to use property wrappers for your case! The below is not an exact solution but can modify/change to accommodate your need
import UIKit
enum PhoneNumberType {
case mobile
}
enum PhoneValidation {
case phoneInValid
case phoneValid
case smsValidationAttempted
case smsValidationFailed
case smsValidationSuccessful
case smsValidationOTPTriggered
}
struct PhonesViewModel {
public var phoneType: PhoneNumberType = PhoneNumberType.mobile
public var phone: String?
public var code: String?
public var countryCode: String?
public var phoneValidation : PhoneValidation?
func validate(value: [PhoneValidation]) -> Bool {
//add proper check here
return false
}
}
#propertyWrapper
struct Wrapper {
private(set) var value: PhonesViewModel? = nil
var validators: [PhoneValidation] = []
var wrappedValue: PhonesViewModel? {
get { value }
set {
if let model = newValue, model.validate(value: validators) {
value = newValue
print("Value assigned")
} else {
print("Value not assigned")
}
}
}
}
struct SomeOtherClass {
#Wrapper(validators: [PhoneValidation.phoneInValid])
var model: PhonesViewModel?
}
var a = SomeOtherClass()
a.model = PhonesViewModel()
a.model = PhonesViewModel()
You can use a technique with the name "popsicle immutability". An object is initially mutable, but can be "frozen". Modifications for frozen objects are forbidden. In your case PhonesViewModel become frozen when isValid property have value smsValidationOTPTriggered or smsValidationSuccessful.
Let's add Freezable protocol for requirements to objects that can become immutable and conforming for PhonesViewModel:
protocol Freezable: class {
var isFrozen: Bool { get }
}
extension PhonesViewModel: Freezable {
var isFrozen: Bool {
isValid == .smsValidationOTPTriggered || isValid == .smsValidationSuccessful
}
}
Now we must add validation for isFrozen value when a property is assigned. It can be added in property observers like:
...
public var phone: String? {
didSet {
validate()
}
}
...
private func validate() {
assert(!isFrozen)
}
Or using property wrapper:
#propertyWrapper
struct Guarded<Value> {
private var value: Value
init(wrappedValue: Value) {
value = wrappedValue
}
#available(*, unavailable)
var wrappedValue: Value {
get { fatalError("only works on instance properties of classes that conforms to Freezable protocol") }
set { fatalError("only works on instance properties of classes that conforms to Freezable protocol") }
}
static subscript<EnclosingSelf: Freezable>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
object[keyPath: storageKeyPath].value
}
set {
precondition(!object.isFrozen, "Object \(object) is frozen! Modifications are forbidden")
object[keyPath: storageKeyPath].value = newValue
}
}
}
So your class will look like:
class PhonesViewModel: NSCopying {
#Guarded
public var phoneType: PhoneNumberType = PhoneNumberType.mobile
#Guarded
public var phone: String?
#Guarded
public var code: String?
#Guarded
public var countryCode: String?
#Guarded
public var isValid : PhoneValidation?
func copy(with zone: NSZone? = nil) -> Any {
let copy = PhonesViewModel()
copy.phoneType = phoneType
copy.phone = phone
copy.code = code
copy.countryCode = countryCode
copy.isValid = isValid
return copy
}
}
I am facing an issue where I am unable to keep existing relationships after calling add(_, update: true) function.
I wrote a TaskSync class that is responsible for creating/updating Task objects:
class TaskSync: ISync {
typealias Model = Task
func sync(model: Task) {
let realm = try! Realm()
let inWrite = realm.isInWriteTransaction
if !inWrite {
realm.beginWrite()
}
let _task = realm.object(ofType: Task.self, forPrimaryKey: model.id)
// Persist matches as they are not getting fetched with the task
if let _task = _task {
print("matches: \(_task.matches.count)")
model.matches = _task.matches
}
realm.add(model, update: true)
if _task == nil {
var user = realm.object(ofType: User.self, forPrimaryKey: model.getUser().id)
if (user == nil) {
user = model.getUser()
realm.add(user!, update: true)
}
user!.tasks.append(model)
}
if !inWrite {
try! realm.commitWrite()
}
}
func sync(models: List<Task>) {
let realm = try! Realm()
try! realm.write {
models.forEach { task in
sync(model: task)
}
}
}
}
When a model is to be synced, I check if it already exists in the Realm and if so, I fetch it and try to include the matches property as this one is not included in the model.
Right before the call realm.add(model, update: true), model contains list of matches, however right after the realm.add is executed, the matches list is empty.
Here are the two models:
class Task: Object, ElementPreloadable, ElementImagePreloadable, ItemSectionable {
dynamic var id: Int = 0
dynamic var title: String = ""
dynamic var desc: String = ""
dynamic var price: Float = 0.0
dynamic var calculatedPrice: Float = 0.0
dynamic var location: String = ""
dynamic var duration: Int = 0
dynamic var date: String = ""
dynamic var category: Category?
dynamic var currency: Currency?
dynamic var longitude: Double = 0.0
dynamic var latitude: Double = 0.0
dynamic var state: Int = 0
dynamic var userId: Int = 0
// Existing images
var imagesExisting = List<URLImage>()
// New images
var imagesNew = List<Image>()
// Images deleted
var imagesDeleted = List<URLImage>()
private let users = LinkingObjects(fromType: User.self, property: "tasks")
var user: User?
var matches = List<Match>()
dynamic var notification: Notification?
override static func ignoredProperties() -> [String] {
return ["imagesExisting", "imagesNew", "imagesDeleted", "user", "tmpUser"]
}
override static func primaryKey() -> String? {
return "id"
}
func getImageMain() -> URLImage? {
for image in imagesExisting {
if image.main {
return image
}
}
return imagesExisting.first
}
func getSection() -> Int {
return state
}
func getSectionFieldName() -> String? {
return "state"
}
func getId() -> Int {
return id
}
func getURL() -> URL? {
if let image = getImageMain() {
return image.getResizedURL()
}
return nil
}
func getState() -> TaskOwnState {
return TaskOwnState(rawValue: state)!
}
func getUser() -> User {
return (user != nil ? user : users.first)!
}
}
class Match: Object, ElementPreloadable, ElementImagePreloadable, ItemSectionable {
dynamic var id: Int = 0
dynamic var state: Int = -1
dynamic var priorityOwnRaw: Int = 0
dynamic var priorityOtherRaw: Int = 0
dynamic var user: User!
var messages = List<Message>()
private let tasks = LinkingObjects(fromType: Task.self, property: "matches")
var task: Task?
dynamic var notification: Notification?
override static func primaryKey() -> String? {
return "id"
}
override static func ignoredProperties() -> [String] {
return ["task"]
}
func getId() -> Int {
return id
}
func getSection() -> Int {
return 0
}
func getURL() -> URL? {
if let image = user.getImageMain() {
return image.getResizedURL()
}
return nil
}
func getPriorityOwn() -> PriorityType {
if priorityOwnRaw == PriorityType.normal.rawValue {
return PriorityType.normal
}
else {
return PriorityType.favorite
}
}
func getPriorityOther() -> PriorityType {
if priorityOtherRaw == PriorityType.normal.rawValue {
return PriorityType.normal
}
else {
return PriorityType.favorite
}
}
func getSectionFieldName() -> String? {
return nil
}
func getTask() -> Task {
return (task != nil ? task : tasks.first)!
}
}
I spent hours trying to figure out why I am unable to keep the matches relationship when updating the task. Every advice will be highly appreciated!
This question was also asked upon Realm's GitHub issue tracker. For posterity, here is the solution.
List properties should always be declared as let properties, as assigning to them does not do anything useful. The correct way to copy all objects from one List to another is model.tasks.append(objectsIn: _user.tasks).
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?
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.