Dynamic Variables in loop - loops

I'm trying to figure out what the best approach would be to handle variables when looping through a slice.
I have the following bit of code:
type Server struct {
Name string
Features []string
}
func main() {
var server1 Server
server1.Name = "server-abc-1"
server1.Features = append(server1.Features, "feature1", "feature2", "feature3" )
subMenuServer1 := systray.AddMenuItem(server1.Name, "Server Menu")
//Manually adding a menu item
subMenuFeatureItem1 := subMenuServer1.AddSubMenuItem("feature1", "feature1 description")
//Creating menu items from looping through slice - Not working
for i, s := range server1.Features {
dynamicVariable := subMenuServer1.AddSubMenuItem(s, "test")
}
}
How would I loop through the features slice to dynamically create the menu items? The main problem is I need to generate a dynamic variable of some sort which is not supported in Go. Is there a better why to do things?
I've found people mentioning using hash table instead of dynamic variables. If so what type does the hash table would I need if the value is going to be "subMenuServer1.AddSubMenuItem(s, "test")"

Creating new variables dynamically is almost always a bad idea, even in languages that support it. Go doesn't support it, since it's a statically compiled language.
You're much better off using a map of type map[string]T, T being the type returned by AddSubMenuItem.

Related

Error when trying to set array in userdefaults: Thread 1: "Attempt to insert non-property list object

I have solved the issue now, thanks for your help. I shouldn't have tried to save arrays with UITextViews, but I should have saved their text as strings instead. Here was the original question:
I have tried a lot, and googled a lot, but I can't solve this problem on my own. Whenever I try to save an array in userdefaults, it just is not working. I get the following error:
Thread 1: "Attempt to insert non-property list object (\n "<UITextView: 0x14001f800; frame = (0 0; 355 180); text = 'D'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600003f01d10>; layer = <CALayer: 0x6000031c83e0>; contentOffset: {0, 0}; contentSize: {355, 30}; adjustedContentInset: {0, 0, 0, 0}>"\n) for key content"
I don't know what a non-property list object is. And I do not know how to solve the problem. Below is the lines of code that do not work.
var contentList: [Any] = []
let cl = defaults.array(forKey: "content")!
if cl.count != 0{
contentList += cl
}
contentList.append(label)
defaults.setValue(contentList, forKey: "content")
If I take out the last line of code by turning it into a comment everything runs just fine. How should I replace that line of code? I essentially want to save an array of UITextViews and make it larger every time I call a fucntion (this code is part of a larger function). The reason why I have created another two lists (cl and contentList) is that it helps me with a problem down the line. What I cannot understand however, is why the last line of code doesn't work. If anyone has any ideas, please help me, it would be much appreciated.
Use only String as stated in comments :
var contentList: [String] = []
let cl = defaults.array(forKey: "content")!
if cl.count != 0{
contentList += cl
}
If lbText = label.text {
contentList.append(lbText)
defaults.setValue(contentList, forKey: "content")
}
You can only store a very limited list of data types into UserDefaults, commonly referred to as "property list objects" (Since property list (or plist) files will only store the same data types.
To quote the Xcode docs on UserDefaults, in the section titled "Storing Default Objects":
A default object must be a property list—that is, an instance of (or for collections, a combination of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary [or Data, String, NSNumber, Date, Array, or Dictionary types in Swift.] If you want to store any other type of object, you should typically archive it to create an instance of Data.
(I added the equivalent Swift types to the above quote in square brackets, since it looks like Apple hasn't updated it for Swift.)
That's worded a little awkwardly. The idea is that you can only store data of the types listed. Because the Array and Dictionary types are "container" types, you can store any combination of arrays and dictionaries that contain combinations of any of the above types. For example, you can store an array that contains a dictionary, 3 dates, 2 floats, a Double, some Data, and 2 arrays, and those dictionaries and arrays can contain other dictionaries and/or arrays.)
It is almost always wrong to archive UIView objects like UITextViews. You should save the text properties of your text views instead.
If you want to manage a vertical stack of UITextView objects, I suggest adding a vertical stack view to your user interface, and then writing code that adds or removes UITextView subviews to your stack view. You should be able to find plenty of examples of adding and removing objects from stack views online. (It's really easy.)
If you want to manage a scrolling list of feeds of arbitrary length, you might want to use a table view or collection view instead. Those require that you set up a data model and implement a "data source". That takes a little practice to get right, but is very powerful.

Iterate through an array in an array of dictionaries swift

I am currently in a bit of a bind.
struct sectionWithDatesAsName {
var sectionName : String
var sectionObjects : [SoloTransactionModel]!
init(uniqueSectionName: String?, sectionObject: [SoloTransactionModel]?) {
sectionName = uniqueSectionName ?? "nil"
if let section = sectionObject {
sectionObjects = section.reversed()
}
}
}
I currently have an array of sectionWithDatesAsName. And I can work with it, display in the tableView among other things.
The bind comes up when I want to check some information in the sectionObject before displaying it on the tableView.
I want to check the type of the sectionObject which is saved in the object itself.
How do I check the information in the sectionObject without slowing down the app? Or have a horrible time complexity calculated?
(Note: I can't change the format of the struct has this has already been used by a whole lot of other processes)
Write a function in your sectionWithDatesAsName with the signature filteredSections(type: sectionType) -> sectionWithDatesAsName
(If you don't have the ability to edit the definition of sectionWithDatesAsName you can create an extension that adds the above function)
If the sectionWithDatesAsName is defined elsewhere, define this function in an extension.
When you call it, build a new sectionWithDatesAsName object by filtering the arrays to match the specified type.
Use the resulting filtered sectionWithDatesAsName object as the data model for your table view. It will be built once and used for the lifetime of the tableView, so you will pay an O(n) time cost to filter it once when you create it.

Go: Define multidimensional array with existing array's type and values?

Is it possible to a)define b)initialize a new multidimensional array using an existing array, like in following code instead of var b [2][3]int, just saying something like var b [2]a ?
Using a's type whatever it is, instead of hardcoding it (which misses the point of using [...] for a).
And perhaps handling initialization=copying of values at the same time?
package main
func main () {
a := [...]int{4,5,6}
var b [2][3]int
b[0],b[1] = a,a
}
(I'm aware of ease and convenience of slices, but this question is about understanding arrays.)
Edit: can't believe I forgot about var b [2][len(a)]int, beginner's brain freeze. One line answer would be var b = [2][len(a)]int{a,a} . That's a type conversion, right?
The following code would also work. Both your example and mine do the same thing and neither should be much faster than the other.
Unless you use reflect to make a slice (not array) of your [3]int, it is impossible to not repeat [3]int in your new type. Even that is not possible in the current release. It is in tip and will be released in Go 1.1.
package main
import "fmt"
func main() {
a := [...]int{4,5,6}
var b = [2][3]int{a, a}
fmt.Println(b)
}

Updating entity in Google Appengine datastore with Go

I am toying with GAE, Go and the datastore. I have the following structs:
type Coinflip struct {
Participants []*datastore.Key
Head string
Tail string
Done bool
}
type Participant struct {
Email string
Seen datastore.Time
}
(For those wondering I store Participants as a slice off Key pointers because Go doesn't automatically dereferences entities.)
Now I want to find a Participant with a particular Email address associated with a know Coinflip. Like so (this works):
coinflip, _ := find(key_as_string, context)
participants, _ := coinflip.fetchParticipants(context) /* a slice of Participant*/
var found *Participant
for i := 0; i < len(participants) && found == nil; i++ {
if participants[i].Email == r.FormValue("email") {
found = &participants[i]
}
}
(*found).Seen = datastore.SecondsToTime(time.Seconds())
How do I save *found to the datastore? I need the key apparently but the coupling between the Participant struct and the Key is very loose.
I'm unsure how to proceed from here. Do I need to return the keys as well from the fetchParticipants call? The Java and Python GAE implementation seem quite a bit simpler (just call put() on the object).
Thanks in advance,
Do I need to return the keys as well from the fetchParticipants call?
Yes. And then call "func Put(c appengine.Context, key *Key, src interface{}) (*Key, os.Error)"
The Java and Python GAE implementation seem quite a bit simpler (just
call put() on the object).
Probably a fair statement. The Go community has a very strong bias against "magic". In this case the Participant struct has two fields that you have declared. Adding the key to it in the background would be considered magic.
For interacting with data in Go, consider using our new library https://github.com/matryer/gae-records for an Active Record, data objects wrapper around the datastore. It sorts out a lot of the hassle for you.
For example, it supports:
// create a new model for 'People'
People := gaerecords.NewModel("People")
// create a new person
mat := People.New()
mat.
SetString("name", "Mat")
SetInt64("age", 28)
.Put()
// load person with ID 1
person, _ := People.Find(1)
// change some fields
person.SetInt64("age", 29).Put()
// load all People
peeps, _ := People.FindAll()
// delete mat
mat.Delete()
// delete user with ID 2
People.Delete(2)
// find the first three People by passing a func(*datastore.Query)
// to the FindByQuery method
firstThree, _ := People.FindByQuery(func(q *datastore.Query){
q.Limit(3)
})
// build your own query and use that
var ageQuery *datastore.Query = People.NewQuery().
Limit(3).Order("-age")
// use FindByQuery with a query object
oldestThreePeople, _ := People.FindByQuery(ageQuery)
// using events, make sure 'People' records always get
// an 'updatedAt' value set before being put (created and updated)
People.BeforePut.On(func(c *gaerecords.EventContext){
person := c.Args[0].(*Record)
person.SetTime("updatedAt", datastore.SecondsToTime(time.Seconds()))
})

Delphi -> Delphi prism, how to use array of records?

I'm learning Delphi Prism, and i don't find how to write the following code with it :
type
TRapportItem = record
Label : String;
Value : Int16;
AnomalieComment : String;
end;
type
TRapportCategorie = record
Label : String;
CategoriesItems : Array of TRapportItem;
end;
type
TRapportContent = record
Categories : array of TRapportCategorie;
end;
Then, somewhere, i try to put items in the array :
rapport.Categories[i].Label:=l.Item(i).InnerText;
But it doesn't work.. Can someone enlight me?
Thanks!
You didn't specify exactly what "didn't work". You should include the error in questions like this.
Arrays are reference types, and they start out with the value nil. They need to be initialized before elements can be accessed.
You can do this with the new operator:
rapport.Categories = new TRapportCategorie[10]; // 0..9
Arrays are quite a low-level type. Usually it's better to work with List<T> instead.
So you'd declare:
Categories: List<TRapportCategorie>;
But lists also need initializing, using the new operator. Also, modifying the return value of the indexer on a list containing a value type will be modifying a copy, not the original, which leads to the next point.
Records are usually not the best data type for representing data, as they are not reference types; it's very easy to end up modifying a copy of the data, rather than the original data. It's usually best to use classes instead, where you can put all the initialization code (such as allocating the array or list) in the constructor.

Resources