I'm trying to modify an existing struct which is then used with an array. Is there a solution to the following?
struct pickerData {
var key = ""
var value = ""
}
var pickerArray = [pickerData]()
pickerArray.append(pickerData(key: "1", value: "2")) //OK up to know but
//I need to append a new key:value to this structure
pickerArray.append(pickerData(key: "1", value: "2",value2: "3")) // error
pickerArray.append(pickerData(key: "1", value: "2"),value2: "3") // error
I basically need a mutable struct, is this doable?
The structure of a struct cannot change; as your comment suggests that you want to add a key:value pair, you should be using a datatype that supports such pairs: a Dictionary. (Technically, those aren't key:value pairs in a struct.)
Related
How to modify the value of key from struct that is under nested of array of struct. I found one of possible solution from stackoverflow but it is only for one level. I am wondering if there is any better solution? and what if the key is optional?
struct Article {
var id: Int
var book: [Book]
}
struct Book {
var page: Int
var author: [Author]
}
struct Author {
var visited: Bool
}
// update value of visited key in nested array of struct
var a = Article(id: 1, book: [Book(page: 11, author: [Author(visited: true)])])
print(a)
a.book.modifyElement(atIndex: 0) {$0.author.modifyElement( atIndex: 0) {$0.visited = false}}
print(a)
Changing The value of struct in an array
"How to modify the value of property from struct that is under nested of array of struct".
Try this approach, a better more compact solution than what you have:
var a = Article(id: 1, book: [Book(page: 11, author: [Author(visited: true)])])
print("\n---> before a: \(a)")
a.book[0].author[0].visited = false // <-- here
print("\n---> after a: \(a)")
How would I change the position of the json values?
What Im trying to achieve:
[{"key":"f","value":"f"},{"value":"f","key":"f"}]
Problem:
type Struct struct {
Key string `json:"key"`
Value string `json:"value"`
}
func main() {
test := []Struct{ {Key: "test",Value: "wep"}, {Value: "wep",Key: "test"}}
bytes, _ := json.Marshal(test)
fmt.Print(string(bytes))
}
Running this code prints [{"key":"test","value":"wep"},{"key":"test","value":"wep"}]
I have also tried doing something like this but it just printed empty values
type Struct struct {
Key string `json:"key"`
Value string `json:"value"`
Value2 string `json:"value"`
Key2 string `json:"key"`
}
But how would I be able to switch the position of the key and value field around?
type StructA struct {
Key string `json:"key"`
Value string `json:"value"`
}
type StructB struct {
Value string `json:"value"`
Key string `json:"key"`
}
func main() {
test := []interface{}{
StructA{Key: "test", Value: "wep"},
StructB{Value: "wep", Key: "test"},
}
bytes, _ := json.Marshal(test)
fmt.Print(string(bytes))
}
https://play.golang.org/p/72TWDU1BMaL
If you're using json.Marshal provided by official package it's not passible to do that. In stead, you can implement your own MarhalJSON method so that you can decide the position of your struct fields.
To the question "can I make a single struct type serialize its fields in a different order or different occasions ?" :
there isn't a simple way to do this.
Regarding struct fields : the code you write shows the assigning operations in a given order, but once your code is compiled, there is no trace of that order anymore.
If you really need this (side note : I would be curious to know about your use case ?), you could create a custom type, with its own .MarshalJSON() method, which would hold a value indicating "fields should be serialized in this order".
If what you need is to send an array of heterogeneous objects, use separate struct types, and an []interface{} array :
type Obj1 struct{
Key string `json:"name"`
Value string `json:"value"`
}
type Obj2 struct{
Value string `json:"value"`
Key string `json:"name"`
}
func main() {
test := []interface{}{ Obj1{Key: "test",Value: "wep"}, Obj2{Value: "wep",Key: "test"}}
bytes, _ := json.Marshal(test)
fmt.Print(string(bytes))
}
https://play.golang.org/p/TOk28gL0eSK
I'm lost at how to initialize the struct below? Basically I want to create an empty variable that represents the struct below, but the values should be optional/nil, but i have no idea how to go about it.
// MARK: - Main
struct Main: Codable {
let meta: Meta
let objects: [Object]
}
// MARK: - Meta
struct Meta: Codable {
let status: String
let count, offset, totalcount: Int
}
// MARK: - Object
struct Object: Codable {
let id:Int
let url: String
let displayname: String
let inventory: [Inventory]
let media: [Media]
}
// MARK: - Inventory
struct Inventory: Codable {
let id, warehouseid, instock, threshold: Int
let reserved: Int
let coordinates, note: String
let prodno: Int
let lastinventory: String
let soldout, onpurchaseorders, generation: Int
let created, changed: String
}
// MARK: - Media
struct Media: Codable {
let id, prodno: Int
let webpath: String
let slot: Int
let type, extdata: String
let ctime, xsize, ysize, mediasetid: Int
let alt, title: String
let generation: Int
let created, changed: String
}
With the below code I get the error message "no exact matches in call to initializer, and a bunch of other errors if i change the code.
var sökresultat3 = Main3()
If you want the properties to be Optionals, then you have to declare them that way. Int means you want an Int. If you want an Optional Int, then declare it Int?.
That said, I would be very thoughtful about creating so many Optionals, and particularly optional arrays and strings. Is there a difference in your system between "no inventory" (nil) and "an empty list of inventory" ([])? Or "no name" (nil) and "empty name" ("")? If these are the same, then you often will prefer to just have default values, not optional values. Optionals add a lot of complexity that you may not need.
As an example of default values, using var will make this much simpler and give you the initializers you're hoping for:
struct Main: Codable {
var meta = Meta()
var objects: [Object] = []
}
// MARK: - Meta
struct Meta: Codable {
var status = ""
var count = 0
var offset = 0
var totalcount = 0
}
If you do make these optional, then var again will create the initializers you're looking for:
struct Main: Codable {
var meta: Meta?
var objects: [Object]?
}
As a rule, simple data structs that have no logic in them should declare their properties var. There are some exceptions, such as Identifiable structs, which should make their id be let because their id has some special meaning. But as a rule, making structs excessively let just makes them hard to use without gaining any benefits. (Values types are never shared, so mutation is not a problem.)
If you still want to use let, you'll need to define your own init by hand.
If all your struct's properties are optionals, and you make them all vars, Swift will create an intializer that defaults all your properties to nil. It is as if you defined your struct as follows:
struct AStruct {
var a: Int?
var string: String?
//You don't have to define this initializer if all your properties are var Optionals
init(a: Int? = nil, string: String? = nil) {
self.a = a
self.string = string
}
}
You can invoke that initializer like this:
var aStruct = AStruct()
As Alexander pointed out, just because you can do this does not mean that you should do it. It does not seem like good practice.
Change main to this
struct Main: Codable {
var meta: Meta?
var objects: [Object]?
}
Context - I'm currently learning Swift Struct. So I decided to create my own Phone structure in Playground. (see below)
Problem -
The downloadApp method on the phone struct is throwing the following error.. Cannot use mutating member on immutable value: 'self' is immutable.
Expect outcome - To peacefully append new strings to my apps property, which is an array of strings.
Swift code
struct Phone {
let capacity : Int
let Brand : Sting
var name: String
let model: String
var apps: [String]
var contacts: [String]
var formatCapacity: String {
return "\(capacity)GB"
}
func downloadApp(name: String){
apps.append(name) // ERROR
}
}
You simply need to mark downloadApp as mutating. The issue is caused by the fact that downloadApp is declared in a struct type, which is a value type and hence if you mutate any properties (namely, the apps array here) of the struct, you actually mutate the struct itself. By marking the function as mutating, the compiler allows such modification of the struct through a member function of the type.
mutating func downloadApp(name: String){
apps.append(name)
}
What I'm looking to try to do is have another var attached to the array to store values in without having to make a 2D array.
var list: NSMutableArray! = NSMutableArray()
list.add("Apple")
list[0].color = red // Something like this
Any help in the right direction will be appreciated
For that make array of custom class or struct.
struct Fruit {
let name: String
let color: String
}
Now make array of this struct and add object of this struct in it.
var fruits = [Fruit]()
fruits.append(Fruit(name: "Apple", color: "red"))
Now you can access object in a way you describe in your question.
print(fruits[0].name) //Apple
print(fruits[0].color) //red
Note: In Swift use swift's type Array and Dictionary instead of NSArray and NSDictionary.