I use xCode 9, swift 4 and "Eureka form library" for my project.
The situation
I have a list of cars with name and unique ID associated this way: 0 - ANY, 1 - VW, 7 - AUDI, 20 - MAZDA
var name_cars: [String] = ["ANY","VW","AUDI","MAZDA"]
var id_cars:[Int] = [0, 1, 7, 20]
I also have a form with "PushRow" and "ButtonRow".
On click to the button I want to print the selected car name and ID.
I was able to print the car's name but not the ID.
import UIKit
import Eureka
class myPage: FormViewController {
var cars: [String] = ["ANY","VW","AUDI","MAZDA"]
var id_cars:[Int] = [0, 1,7,20]
var selected_car: String = "ANY" //default car
var selected_car_id: Int = 0 //default id car
override func viewDidLoad() {
super.viewDidLoad()
create_form()
}
func create_form(){
form
+++ Section("List")
//list
<<< PushRow<String>() {
$0.title = "Cars"
$0.options = cars
$0.value = "ANY"
$0.tag = "list_element"
$0.selectorTitle = "Choose car"
$0.onChange { [unowned self] row in
self.selected_car = row.value!
self.selected_car_id = ??? // **what should it be here in order to get the ID**
}
}
//button
<<< ButtonRow("Button1") {row in
row.title = "Get Value on Console"
row.onCellSelection{[unowned self] ButtonCellOf, row in
print ("Car selected = ",self.selected_car, " and Id_Car_Selected = ",self.selected_car_id)
}
}
}
}
First of all please conform to the naming convention that class names start with a capital letter and variable names are lowerCamelCased rather than snake_cased.
Swift is an object oriented language. Rather than two separate arrays use a custom struct Car.
import UIKit
import Eureka
struct Car : Equatable {
let name : String
let id : Int
}
The push row is declared as PushRow<Car>() and the property displayValueFor is populated with the name
class MyPage: FormViewController {
let cars = [Car(name: "ANY", id: 0), Car(name: "VW", id: 1), Car(name: "AUDI", id: 7), Car(name: "MAZDA", id: 20)]
var selectedCar : Car!
override func viewDidLoad() {
super.viewDidLoad()
selectedCar = cars[0]
createForm()
}
func createForm() {
form
+++ Section("List")
//list
<<< PushRow<Car>() {
$0.title = "Cars"
$0.options = cars
$0.value = selectedCar
$0.displayValueFor = {
guard let car = $0 else { return nil }
return car.name
}
$0.tag = "list_element"
$0.selectorTitle = "Choose car"
$0.onChange { [unowned self] row in
self.selectedCar = row.value!
}
}
//button
<<< ButtonRow("Button1") {row in
row.title = "Get Value on Console"
row.onCellSelection{[unowned self] ButtonCellOf, row in
print ("Car selected = ", self.selectedCar.name, " and Id_Car_Selected = ", self.selectedCar.id)
}
}
}
}
Related
I've class and inside of a class got struct GoalsDifference, in that struct there are two propertys: scoredGoal and passedGoal which's value is passed by me.
I've declared two variables with this class and struct and put them in array.
Now I want to get into the array and compare the first variable's scoredGoal to the other one ( as well as passedGoals to each other )
class Team: Base {
var goalsDifference: GoalsDifference?
override init(name:String){
super.init(name: name)
}
convenience init(name:String, goalsDifference:GoalsDifference){
self.init(name:name)
self.goalsDifference = goalsDifference
}
struct GoalsDifference {
var scoredGoal:Int
var passedGoal:Int
}
}
var team1 = Team(name:"Team one", goalsDifference: .init(scoredGoal: 3, passedGoal: 5))
var team2 = Team(name:"Team two", goalsDifference: .init(scoredGoal: 3, passedGoal: 2))
var twoTeams = [team1,team2]
I tried to do it with .filter method but it returns an error : Contextual closure type '(Team) throws -> Bool' expects 1 argument, but 2 were used in closure body
twoTeams[0..<teamsCount].filter { $0.goalsDifference?.scoredGoal ?? "" > $1.goalsDifference?.scoredGoal ?? ""}
This gets a little cumbersome since goalDifference is optional but here is a solution with a function that compares self with another team. I assume that this is sports related and that goals always start at 0.
extension Team {
private static let emptyGoalsDifferenc = GoalsDifference(scoredGoal: .zero, passedGoal: .zero)
func best(goals: KeyPath<GoalsDifference, Int>, comparing other: Team) -> Team? {
let ownDifference = self.goalsDifference ?? Self.emptyGoalsDifferenc
let otherDifference = other.goalsDifference ?? Self.emptyGoalsDifferenc
let ownGoals = ownDifference[keyPath: goals]
let otherGoals = otherDifference[keyPath: goals]
if ownGoals == otherGoals { return nil }
return ownGoals > otherGoals ? self : other
}
}
Example
var team1 = Team(name:"Team one", goalsDifference: .init(scoredGoal: 3, passedGoal: 5))
var team2 = Team(name:"Team two", goalsDifference: .init(scoredGoal: 3, passedGoal: 2))
let bestScored = team1.best(goals: \.scoredGoal, comparing: team2)
let bestPassed = team1.best(goals: \.passedGoal, comparing: team2)
I am trying to convert Realm Object into JSON. My version is working but not if you want to put multiple objects into JSON. So my question is, how should you add multiple Realm Objects into JSON?
Something like that:
{
"Users": [
{"id": "1","name": "John"},{"id": "2","name": "John2"},{"id": "3","name": "John3"}
],
"Posts": [
{"id": "1","title": "hey"},{"id": "2","title": "hey2"},{"id": "3","title": "hey3"}
]
}
This is what I am doing right now:
func getRealmJSON(name: String, realmObject: Object, realmType: Any) -> String {
do {
let realm = try Realm()
let table = realm.objects(realmType as! Object.Type)
if table.count == 0 {return "Empty Table"}
let mirrored_object = Mirror(reflecting: realmObject)
var properties = [String]()
for (_, attr) in mirrored_object.children.enumerated() {
if let property_name = attr.label as String! {
properties.append(property_name)
}
}
var jsonObject = "{\"\(name)\": ["
for i in 1...table.count {
var str = "{"
var insideStr = String()
for property in properties {
let filteredTable = table.value(forKey: property) as! [Any]
insideStr += "\"\(property)\": \"\(filteredTable[i - 1])\","
}
let index = insideStr.characters.index(insideStr.startIndex, offsetBy: (insideStr.count - 2))
insideStr = String(insideStr[...index])
str += "\(insideStr)},"
jsonObject.append(str)
}
let index = jsonObject.characters.index(jsonObject.startIndex, offsetBy: (jsonObject.count - 2))
jsonObject = "\(String(jsonObject[...index]))]}"
return jsonObject
}catch let error { print("\(error)") }
return "Problem reading Realm"
}
Above function does like that, which is good for only one object:
{"Users": [{"id": "1","name": "John"},{"id": "2","name": "John2"},{"id": "3","name": "John3"}]}
Like this I call it out:
let users = getRealmJSON(name: "Users", realmObject: Users(), realmType: Users.self)
let posts = getRealmJSON(name: "Posts", realmObject: Posts(), realmType: Posts.self)
And I tried to attach them.
Can anybody please lead me to the right track?
You can use data models to encode/decode your db data:
For example you have
class UserEntity: Object {
#objc dynamic var id: String = ""
#objc dynamic var createdAt: Date = Date()
#objc private dynamic var addressEntities = List<AddressEntity>()
var addresses: [Address] {
get {
return addressEntities.map { Address(entity: $0) }
}
set {
addressEntities.removeAll()
let newEntities = newValue.map { AddressEntity(address: $0) }
addressEntities.append(objectsIn: newEntities)
}
}
}
Here you hide addressEntities with private and declare addresses var with Address struct type to map entities into proper values;
And then use
struct User: Codable {
let id: String
let createdAt: Date
let addresses: [Address]
}
And then encode User struct any way you want
I've already check all of those topics:
How to save an array of custom struct to NSUserDefault with swift?
How to save struct to NSUserDefaults in Swift 2.0
STRUCT Array To UserDefaults
I have a struct containing some Strings and an other struct: MySection.
struct MySection {
var name: String = ""
var values: [MyRow] = []
}
And there is MyRow which is store in MySection.values
struct MyRow {
var value: String = ""
var quantity: String = ""
var quantityType: String = ""
var done: String = ""
}
Two arrays for use it
var arraySection: [MySection] = []
var arrayRow: [MyRow] = []
And in my application, I add dynamically some values in those arrays.
There is the delegate method for get datas from my second ViewController
func returnInfos(newItem: [MyRow], sectionPick: String) {
arrayRow.append(MyRow())
arrayRow[arrayRow.count - 1] = newItem[0]
manageSection(item: sectionPick)
listTableView.reloadData()
}
And there is the manageSection function.
func manageSection(item: String) {
var i = 0
for _ in arraySection {
if arraySection[i].name == item {
arraySection.insert(MySection(), at: i + 1)
arraySection[i + 1].values = [arrayRow[arrayRow.count - 1]]
return
}
i += 1
}
arraySection.append(MySection())
arraySection[arraySection.count - 1].name = item
arraySection[arraySection.count - 1].values = [arrayRow[arrayRow.count - 1]]
}
My need is to store datas of the two arrays in UserDefaults (or CoreData maybe??) and use these datas when the user going back to the application.
I don't know how to do it, I've already try methods from the 3 topics but I'm not even doing a good job.
How can I do it?
Thanks guys!
Since both types contain only property list compliant types a suitable solution is to add code to convert each type to a property list compliant object and vice versa.
struct MySection {
var name: String
var values = [MyRow]()
init(name : String, values : [MyRow] = []) {
self.name = name
self.values = values
}
init(propertyList: [String: Any]) {
self.name = propertyList["name"] as! String
self.values = (propertyList["values"] as! [[String:String]]).map{ MyRow(propertyList: $0) }
}
var propertyListRepresentation : [String: Any] {
return ["name" : name, "values" : values.map { $0.propertyListRepresentation }]
}
}
struct MyRow {
var value: String
var quantity: String
var quantityType: String
var done: String
init(value : String, quantity: String, quantityType: String, done: String) {
self.value = value
self.quantity = quantity
self.quantityType = quantityType
self.done = done
}
init(propertyList: [String:String]) {
self.value = propertyList["value"]!
self.quantity = propertyList["quantity"]!
self.quantityType = propertyList["quantityType"]!
self.done = propertyList["done"]!
}
var propertyListRepresentation : [String: Any] {
return ["value" : value, "quantity" : quantity, "quantityType" : quantityType, "done" : done ]
}
}
After creating a few objects
let row1 = MyRow(value: "Foo", quantity: "10", quantityType: "Foo", done: "Yes")
let row2 = MyRow(value: "Bar", quantity: "10", quantityType: "Bar", done: "No")
let section = MySection(name: "Baz", values: [row1, row2])
call propertyListRepresentation to get a dictionary ([String:Any]) which can be saved to User Defaults.
let propertyList = section.propertyListRepresentation
Recreation of the section is quite easy, too
let newSection = MySection(propertyList: propertyList)
Edit
Use the propertyList initializer only if you get data from UserDefaults in all other cases use the other initializer.
For example replace
#IBAction func addButtonPressed(_ sender: Any) {
newProducts.append(MyRow(propertyList: ["":""]))
newProducts[newProducts.count - 1].value = nameTextField.text!
newProducts[newProducts.count - 1].quantity = quantityTextField.text!
newProducts[newProducts.count - 1].quantityType = type
newProducts[newProducts.count - 1].done = "No"
delegate?.returnInfos(newItem: newProducts, sectionPick: typePick)
navigationController?.popViewController(animated: true)
}
with
#IBAction func addButtonPressed(_ sender: Any) {
let row = MyRow(value: nameTextField.text!,
quantity: quantityTextField.text!,
quantityType: type,
done: "No")
newProducts.append(row)
delegate?.returnInfos(newItem: newProducts, sectionPick: typePick)
navigationController?.popViewController(animated: true)
}
and replace
func returnInfos(newItem: [MyRow], sectionPick: String) {
arrayRow.append(MyRow(propertyList: ["":""]))
arrayRow[arrayRow.count - 1] = newItem[0]
manageSection(item: sectionPick)
listTableView.reloadData()
}
with
func returnInfos(newItem: [MyRow], sectionPick: String) {
arrayRow.append(newItem[0])
manageSection(item: sectionPick)
listTableView.reloadData()
}
Basically first create the object, then append it to the array. The other way round is very cumbersome.
i was making a family class when it popped up an error it was "expected declaration" i'm not sure what it means and how to debug it
//
// ViewController.swift
// familyClassSecond
//
// Created by Dordor Zheng on 11/13/16.
// Copyright © 2016 Dordor Zheng. All rights reserved.
//
import UIKit
class Person {
var name : String!
var age : String!
var idNum : Int!
init(name:String, age:String, idNum:Int){
self.name = name
self.age = age
self.idNum = idNum
}
func sayPerson() -> String{
let S = "Hi i'm \(name) i am \(age) years old and my id is \(idNum)"
print(S)
return S
}
}
class female : Person {
var sex : String = "female"
override func sayPerson() -> String {
let S = "Hi i'm \(name) and i am \(age) years old"
print(S)
return S
}
}
class male : Person {
var sex : String = "male"
override func sayPerson() -> String {
let S = "Hi i'm \(name) and i am \(age) years old"
print(S)
return S
}
}
class daughter: female {
var mother : female!
var father : male!
var sibbling : Array<Person>! = []
init(me:female,father:male,mother:female,brother:male){
super.init(name: me.name, age: me.age, idNum: me.idNum)
self.father = father
self.mother = mother
}
override func sayPerson() -> String {
let S = "I'm \(name), i am \(age) years old my father is \(father.name) and my mother is \(mother.name)"
print(S)
return S
}
func appendSibbling(brother:Person){
sibbling.append(brother)
}
}
class brother: male {
var mother : female!
var father : male!
var sibbling : Array<Person>! = []
init(me:male,father:male,mother:female,daughter:female){
super.init(name: me.name, age: me.age, idNum: me.idNum)
self.father = father
self.mother = mother
}
override func sayPerson() -> String {
let S = "I'm \(name), i am \(age) years old my father is \(father.name) and my mother is \(mother.name)"
print(S)
return S
}
}
class father: male {
var wife : female!
var children : Array<Person>! = []
init(me:male, wife:female,child:Person,brother:male){
super.init(name: me.name, age: me.age, idNum: me.idNum)
self.wife = wife
self.children.append(child)
self.children.append(brother)
}
if(children.count == 1 || children.count == 0){
var choose = "child"
}else{
choose = "children"
}
override func sayPerson() -> String {
let S = "I'm \(name), i am \(age) years old i have \(children.count) children and my wife is \(wife.name)"
print(S)
return S
}
}
class mother: female {
var husband : male!
var children : Array<Person>! = []
init(me:female, husband:male,child:Person,brother:male){
super.init(name: me.name, age: me.age, idNum: me.idNum)
self.husband = husband
self.children.append(child)
self.children.append(brother)
}
override func sayPerson() -> String {
let S = "I'm \(name), i am \(age) years old i have \(children.count) children and my husband is \(husband.name)"
print(S)
return S
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let one = female(name: "Dordor", age: "8", idNum: 388313)
let two = male(name: "Tiger", age: "24", idNum: 773424)
let three = male(name: "Chiwen", age: "48", idNum: 143303)
let four = female(name: "Hongwen", age: "47", idNum: 243332)
let child = daughter(me: one, father: three, mother: four, brother: two)
let mom = mother(me: four, husband: three, child: one,brother:two)
let dad = father(me: three, wife: four, child: one,brother: two)
let bigB = brother(me: two, father: three, mother: four, daughter: one)
child.sayPerson()
mom.sayPerson()
dad.sayPerson()
bigB.sayPerson()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
do you have any ideas and the error is on the if
you can copy paste into your code cause i'm using swift 9.2(it's not beta)
You need to make choose a computed property:
var choose : String {
if children.count == 1 || children.count == 0 {
return "child"
} else {
return "children"
}
}
You can pick between two options that you have
Convert choose to a lazy variable:
lazy var choose: String = {
if(self.children.count == 1 || self.children.count == 0){
return "child"
} else {
return "children"
}
}()
Make choose a function:
func choose() -> String {
if(self.children.count == 1 || self.children.count == 0){
return "child"
}else{
return "children"
}
}
I'm making easy example.
I'm trying to filter movies by year using func: filterByYear.
I have an error in one line on the bottom:
'var filterYear = MovieArchive.filterByYear(1980)' Compiler info is: 'Type 'MovieArchive' has no member filterByYear’
import UIKit
class Movie {
let title: String
let director: String
let releaseYear: Int
init(title: String, director: String, releaseYear: Int){
self.title = title
self.director = director
self.releaseYear = releaseYear
}
}
class MovieArchive{
var movies : [Movie]
init(movies:[Movie]){
self.movies = movies
func filterByYear(year:Int) -> [Movie]{
var filteredArray = [Movie]()
for movie in movies{
if movie.releaseYear == year {
filteredArray.append(movie)
}
}
return filteredArray
}
}
}
var newMovie1 = Movie(title: "IT", director: "S.S", releaseYear: 1980)
var newMovie2 = Movie(title: "PP", director: "O.N", releaseYear: 2003)
var moviesArray = [newMovie1, newMovie2]
var myArchive = MovieArchive(movies: moviesArray)
var filterYear = MovieArchive.filterByYear(1980)
var firstMovie = filterYear[0]
print(firstMovie)
You are calling the method on the class itself, not an instance of it. You would have to create an instance of the class like this:
let myMovieArchive = MovieArchive(movies: [Some Array])
and then call the method on the instance.
print(myMovieArchive.filterByYear)
So in your case, call it on myArchive, not MovieArchive.
Even though the question has been answered, you can simplify your filterByYear method to make it a bit more Swifty:
func filterByYear(year:Int) -> [Movie]
{
return movies.filter({ $0.releaseYear == year })
}