Swift Eureka SelectableSection baseValue doesn't work correctly - ios

I have this code for Eureka library:
let section = SelectableSection<ImageCheckRow<String>, String>("Section:", selectionType: .MultipleSelection)
section.tag = "section"
for obj in arrList {
section <<< ImageCheckRow<String>(obj.name){ row in
row.title = obj.name
row.selectableValue = obj.name
row.baseValue = obj.id
row.value = nil
}
}
this shows selectable list, but next code doensn't work as it should:
#IBAction func saveAction(sender: AnyObject) {
let section = self.form.sectionByTag("section") as? SelectableSection<ImageCheckRow<String>, String>
for obj in section!.selectedRows() {
print(obj.baseValue)
}
}
this prints name field, but needs to print id(row.baseValue = obj.id).
Am i doing something wrong here?

I had been reviewing your code and I found this , seems that if we use SelectableSection we need to use selectableValue instead of baseValue for our proposes, but I think that this is an bug from Eureka because selectableValue and baseValue are the same although we set different values
you can mitigate this using row.selectableValue = obj.id instead of row.selectableValue = obj.name
Edited
try this for Int values in selectableValue replace
<ImageCheckRow<String>, String> for <ImageCheckRow<Int>, Int>
also replace section <<< ImageCheckRow<String>(obj.name) for section <<< ImageCheckRow<Int>(obj.name)
and finally adjust saveAction as I do
#IBAction func saveAction(sender: AnyObject) {
let section = self.form.sectionByTag("section") as? SelectableSection<ImageCheckRow<Int>, Int>
for obj in section!.selectedRows() {
print(obj.baseValue)
}
}
this works for me with Int on selectableValue
The problem is this
public final class ImageCheckRow<T: Equatable>: Row<T, ImageCheckCell<T>>, SelectableRowType, RowType {
public var selectableValue: T?
required public init(tag: String?) {
super.init(tag: tag)
displayValueFor = nil
}
}
the selectableValue is of type a pattern for any type you pass in declaration that is why <ImageCheckRow<Int>, Int> resolve the problem with Int
I hope this helps you, regards

Related

Return a single String from a dictionary using uniqueKeysWithValues

Goal of the code:
To assign a struct dictionary with Strings as Keys and String Arrays as values to a variable and then pull one (can be at random) specific String key value in the String Array and return that one String element in the underlying String Array so that it can be used elsewhere (potentially assigned to a label.text)
Essentially (please reference code below), I want to access one value at random in myDictionary using a specific key ("keyOne"), and pull, let's say, "Value2" then return only the string "Value2" from the underlying String Array associated with "keyOne" using indexing.
Errors are in the code below.
The issue I'm thinking is that I haven't figured out how to turn my final var Testing = dict["keyOne"] into an Int compatible index... if it was an index, the code would pull an Int value and the corresponding String from the three Strings in the underlying value array (due to the three String values associated with "keyOne").
Also, variableView() just inherits the datasource from several other containers, but the var dataSource : Structure? is the main reference, so that is what I included.
Code so far:
let myDictionary = [Structure(name: "keyOne", text: ["Value1", "Value2", "Value3"]), Structure(name: "keyTwo", text: ["Value4", "Value5", "Value6"])]
lazy var dict = Dictionary(uniqueKeysWithValues: myDictionary.lazy.map { ($0.name, $0.text) })
struct Structure: Hashable {
var name: String
var text: [String]
init(name: String, text: [String]){
self.name = name
self.text = text
}
}
func variable(at index: Int) -> variableView {
let variable = variableView()
var Testing = dict["keyOne"]
variable.dataSource = Testing![index] <- Cannot assign value of type 'String' to type 'structure'
return variable
var dataSource : Structure? {
didSet {
label.text = "This is a test"
} else {
// n/a
}
}
Please note that the error message is above in the code for variable.dataSource = Testing![index].
I am also suspecting that my issue lies in the "looping" logic of how I am assigning a variable with a struct, to a datasource which references that same struct.
Any help is appreciated as I have been stuck on this for legitimately a week (I truly have exhausted every single StackOverflow answer/question pair I could find).
THANK YOU!
EDIT:
I found this documentation to assist me greatly with this, and I recommend anyone with a similar question as mine to reference this: https://swift.org/blog/dictionary-and-set-improvements/
Given the question and the discussion in the comments I would add a mutating func to the struct that removes and returns a random string
mutating func pullText() -> String? {
guard let index = text.indices.randomElement() else {
return nil
}
return text.remove(at: index)
}
Example
if let index = myDictionary.firstIndex(where: { $0.name == "keyOne" }),
let text = myDictionary[index].pullText() {
someLabel.text = text
}
Here is another example based on the code in the question
Assuming VariableView looks something like this
struct VariableView: View {
var dataSource : Structure?
var word: String?
var body: some View {
Text(word ?? "")
}
}
Then the func variable can be changed to
func variable() -> VariableView {
var variable = VariableView()
if let index = dict.firstIndex(where: { $0.name == "keyOne" }) {
variable.dataSource = dict[index]
variable.word = dict[index].pullText()
}
return variable
}

How do I Bind to a value stored in an Array or Dictionary? Bizarre/Inaccurate Errors reported by Xcode

Can anyone explain why this is not allowed...
Given the following class:
class CandidateAttribute {
var attributeType : AttributeType
var name : String
var value = ""
init(attributeType: AttributeType) {
self.attributeType = attributeType
self.name = attributeType.wrappedName
self.value = ""
}
}
And a class that has a Dictionary of these objects:
class Wrapper {
var candidates : [String: CandidateAttribute]()
// other code
func getCandidateAttribute(attributeType: AttributeType) -> CandidateAttribute{
if let candidate = attributesDict[attributeType.wrappedName] {
return candidate
}
let newCandidate = CandidateAttribute(attributeType: attributeType)
attributesDict[attributeType.wrappedName] = newCandidate
return newCandidate
}
}
Why can't I bind to a CandidateAttribute.value in the following code:
private func addAttributeRow(attributeType: AttributeType) -> some View {
let candidateAttr = candidateItem.getCandidateAttribute(attributeType: attributeType)
return HLabelTextField(label: candidateAttr.name,
hint: "Set value",
value: $candidateAttr.value) //candidateAttr.value)
}
With the code
return HLabelTextField(label: candidateAttr.name,
hint: "Set value",
value: candidateAttr.value)
I get the error Cannot convert value of type 'String' to expected argument type 'Binding<String>'
With the code:
return HLabelTextField(label: candidateAttr.name,
hint: "Set value",
value: $candidateAttr.value)
I get the error Use of unresolved identifier '$candidateAttr'
Is this down to:
a bug in my code?
a language limitation (Binding to objects stored in arrays is not allowed)?
Something else (e.g. I'm holding it wrong)?
If the reason is 2 that seems like a pretty poor language feature to me. The more I use SwiftUI the more I find it requires a lot of work-arounds because things don't 'just work'
Note: I have also tried making CandidateAttribute a struct as well...
As a workaround I can modify CandidateAttribute and add the following function:
func getValueBinding() -> Binding<String> {
let binding = Binding<String>(get: { () -> String in
return self.value
}) { (newValue) in
// This func updates the database
self.value = newValue
}
return binding
}
and change the referencing code to:
private func addAttributeRow(attributeType: AttributeType) -> some View {
let candidateAttr = candidateItem.getCandidateAttribute(attributeType: attributeType)
return HLabelTextField(label: candidateAttr.name,
hint: "Set value",
value: candidateAttr.getValueBinding()) //candidateAttr.value)
}
But that feels like way too much code to simply reference a value.

Swift - A function is only returning nil after appending key values from a dict?

New to Swift. Have some understanding of classes. I have a getSomething() function that is supposed to return an array of key values (not the value itself, but only their keys) appended from a dict. However, my function is only returning nil
public class MyClass {
private var somethingA : String
private var somethingB : String
private var somethingC : Int
// A dictionary
// For example, if I add a fruit, color and price
// ["Apple":["red":5]]
private var complexes:[String:[String:Int]] = [String:[String:Int]]();
init() {
self.somethingA = "";
self.somethingB = "";
self.somethingC = 0;
self.complexes = [somethingA:[somethingB:somethingC]];
}
// Adds a string to the dict complexes
// For example, ["Apple] = ["", 0]
public func addSomething(somethingAA : String) {
self.somethingA = somethingAA;
self.complexes[somethingAA] = [self.somethingB : self.somethingC];
}
// Adds a whole entry to the dict complexes
// For example, ["Apple"] = ["red": 5]
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
complexes[somethingAA] = [complex.somethingBB: complex.somethingCC]
}
// My Problem: only returns nil
public func getSometing() -> [String]?{
var myArray:[String]? = nil;
let keys = Array(complexes.keys);
for key in keys { myArray?.append(key); } // This may be the line of code that isn't properly working
return myArray;
}
}
My testing file:
var sampleObject:MyClass;
sampleObject = MyClass();
sampleObject.addSomething(somethingAA: "Apple");
sampleObject.addSomething(somethingAA: "Orange");
print(sampleObject.getSomething());
My getSomething() function only prints nil meaning that it's not appending the proper keys into myArray
Not exactly sure why. Haven't really worked or familiar with nils since this is my first few days with Swift but I have worked with nulls in Java and C#. Are nils equivalent to nulls?
The correct output that I want should be returning like:
["Apple", "Orange"] // not necessarily in order
You haven't initialised the array. So this is how it should be :
public func getSometing() -> [String]?{
var myArray = [String]();
let keys = Array(complexes.keys);
for key in keys { myArray?.append(key); } // This may be the line of code that isn't properly working
return myArray;
}
Your getSometing() function should be like this,
public func getSometing() -> [String]?{
var myArray:[String] = [];
let keys = Array(complexes.keys);
for key in keys { myArray.append(key);}
return myArray;
}
your are not yet instantiated myArray. Try
var myArray:[String]? = [String]();
Problem is in your getSomething method:
// this is nil, there is no object in myArray, because you initialise it to nil
var myArray:[String]? = nil;
let keys = Array(complexes.keys);
for key in keys { myArray?.append(key); } // since myArray is nil, this does nothing
// and you return nil
return myArray;
So either initialise the array properly:
var myArray:[String]? = [] // this will create new empty array
Or do it even simpler:
public func getSomething() -> [String]?{
return Array(complexes.keys)
}

Eureka SelectableSection get value from selectedRows

I have problem with selectedRows() in SelectableSection.
Using Xcode 8, Swift 3, Eureka 2.0.0-beta.1.
func viewDidLoad() {
let branch_section = SelectableSection<ImageCheckRow<String>>("Branches", selectionType: .multipleSelection)
branch_section.tag = "branch_section"
for branch in branchList {
let branchStr = String(branch.id)
branch_section <<< ImageCheckRow<String>(branch.name){ row in
row.title = branch.name
row.selectableValue = branchStr
row.value = nil
}
}
}
#IBAction func saveFilter(_ sender: AnyObject) {
let branch_section = self.form.sectionBy(tag: "branch_section") as? SelectableSection<ImageCheckRow<String>>
invoiceParams["branches"] = branch_section!.selectedRows().map({$0.value!})
}
now i have problem with this line invoiceParams["branches"] = branch_section!.selectedRows().map({$0.value!})
map' produces '[T]', not the expected contextual result type
'AnyObject?'
What is problem here? This worked with previous versions on swift 2.3.
As far as I can see from SelectableSection.swift selectedRows returns an array of SelectableRow items:
public func selectedRows() -> [SelectableRow] {
return filter({ (row: BaseRow) -> Bool in
row is SelectableRow && row.baseValue != nil
}).map({ $0 as! SelectableRow})
}
So the map function also returns an array.
Your invoiceParams seems to be a dictionary that expects AnyObject? as value.
You can try to change the declaration of invoiceParams to something like var invoiceParams: [String: [Any]] = [:].
Since I don't know Eureka this is just a guess. But I hope it still helps a little.

Construct typed dictionary using swift

I would like to create a typed map (Dictionary) class to meet the following requirements:
func testMap() {
var map = ActivitiesMap()
var activity = Activity()
activity.title = "Activity 1"
activity.uuid = "asdf1234"
map[activity.uuid] = activity
for (key, mapActivity) in map {
logger.debug("ACTIVITY MAP: \(key)=\(mapActivity)")
}
}
In short, I want this class to both be a dictionary such that it can be used in the for loop, however I want to ensure the keys are strings and the values are Activity objects.
I tried many variations of inheriting from Dictionary or typing the class, but so far it's resulted in multiple errors.
EDIT:
I don't think a simple generic dictionary will work, such as String:Activity. I want to have extra methods in the ActivityMap class, such as getAllActivitiesBetweenDates().
I need an actual class definition, not a generic dictionary expression.
You can make it looks like dictionary by implement subscript operator
And conform to Sequence protocol to support for-in loop
struct ActivitiesMap : Sequence {
var map = [String:Activity]()
subscript(key: String) -> Activity? {
get {
return map[key]
}
set(newValue) {
map[key] = newValue
}
}
func generate() -> GeneratorOf<(String, Activity)> {
var gen = map.generate()
return GeneratorOf() {
return gen.next()
}
}
// I can't find out type of map.generator() now, if you know it, you can do
//func generate() -> /*type of map.generator()*/ {
// return map.generate();
//}
}
This works for me. Not sure what is in your ActivitiesMap class, but just typed a Dictionary
class Activity{
var title:String = "";
var uuid: String = "";
}
func testMap() {
//var map = ActivitiesMap()
var map: Dictionary< String, Activity> = Dictionary< String, Activity>();
var activity = Activity()
activity.title = "Activity 1"
activity.uuid = "asdf1234"
map[activity.uuid] = activity
for (key, mapActivity) in map {
println("ACTIVITY MAP: \(key)=\(mapActivity)")
}
}
testMap();
This is my output:
ACTIVITY MAP: asdf1234=C11lldb_expr_08Activity (has 2 children)
class Activity {
var title=""
var id=""
init(id:String, title:String) { self.id=id; self.title = title }
}
var activities = [String:Activity]()
let a1 = Activity(id:"a1", title:"title1")
let a2 = Activity(id:"a2", title:"title2")
let a3 = Activity(id:"a3", title:"title3")
activities[a1.id] = a1
activities[a2.id] = a2
activities[a3.id] = a3
for (id,activity) in activities {
println("id: \(id) - \(activity.title)")
}
should print
id: a2 - title2
id: a3 - title3
id: a1 - title1
(key order not guaranteed to be the same)
You can use typealias keyword to define nice name of any type.
Here is how it can be used for your code:
class Activity { /* your code */ }
typealias ActivityMap = Dictionary<String, Activity>
var activityDict = ActivityMap()
And to support custom functions you can write an extension, example bellow:
extension Dictionary {
func getAllActivitiesBetweenDates(fromDate:NSDate, toDate:NSDate) -> Array<Activity>
// your code
return []
}
}
Usage:
let matchedActivities = activityDict.getAllActivitiesBetweenDates(/*date*/, /*date*/)

Resources