I am new to Swift and I am stuck on an error that must be stupid!!! Here is the code
import Foundation
struct Serie {
var nomeEsercizio = ""
var ripetizioni=0
var chili=0.0
var recupero=0
}
struct Superserie {
var elementi: [Serie] = []
}
struct Scheda {
var elementi: [Superserie] = []
}
class Schede {
var elementi: [Scheda] = []
func isEmpty() -> Bool {
return elementi.isEmpty
}
}
class GestoreDiSchede {
static var schedeLocali = Schede()
static var username = "empty"
class func initializeUserDefaults () {
var superserieTemp = Superserie()
var scheda = Scheda()
let schede = Schede()
superserieTemp.elementi.append(Serie(nomeEsercizio: "Spinte manubri", ripetizioni: 10, chili: 10, recupero: 0)) //....more code
I cannot post the screenshot of the debugger but here the values of the items of the variable "elementi" inside the struct "superserieTemp" are assigned RANDOMLY!!!!! why?
I have tried everything but I am not able to get the code working, please help :(
EDIT <-----------
After some hours I found out that the error occurs because I am not able to properly initialise a struct of array of struct. How can I do it?
If I do the following way, then when I try to append an item in the array inside the bigger struct, I get this error "variable 'a' passed by reference before begin initialised". The 'a' variable refers to the code below.
struct Inside {
var something: String
var somethingElse: Int
}
struct Outside {
var array: [Inside]
init(){
self.array = []
}
}
//then the error is given in the following lines (which are placed inside a method of another class)
var a: Outside
a.array.append.(Inside("aaaa",1111))
Where is the issue?
EDIT EDIT <-----------
this it the right (not compiling) code, I had written the previous one directly in stack overflow
struct Inside {
var something: String
var somethingElse: Int
}
struct Outside {
var array: [Inside]
init(){
self.array = []
}
}
//then the error is given in the following lines (which are placed inside a method of another class)
var a: Outside
a.array.append(Inside(something: "aaaa",somethingElse: 1111))
In your example code you aren't initializing the variable a but in Swift every value has to be initialized before useable. When changing the last two lines to this:
var a = Outside()
a.array.append(Inside(something: "aaaa", somethingElse: 1111))
it works for me just fine (Swift 2.0)
Or you can remove the custom initializer which prevented the default initializer from being generated, then it looks like this:
struct Inside {
var something: String
var somethingElse: Int
}
struct Outside {
var array: [Inside]
}
let a = Outside(array: [Inside(something: "aaaa", somethingElse: 1111)])
A few errors with your code: (1) a is not initialized. You just declared it being of type Outside. (2) You have an extra dot after append. (3) You need parameter labels with the default initializer for Inside.
struct Inside {
var something: String
var somethingElse: Int
}
struct Outside {
var array = [Inside]() // Don't need to initialize array in your init call
}
var a = Outside()
a.array.append(Inside(something: "aaaa",somethingElse: 1111))
Related
I am trying to read and/or console print on of the elements of my array which consist of 28 structs. I can not access any of the struct on my array is says that "Cannot call value of non-function type '[Ficha]'" and I can't find why.. Sorry kind of a newbie on swift.. The section commented is where I discovered the problem but I can't even print one of the elements.
Please help
import UIKit
import Foundation
struct Ficha {
var numero: Int
var ladoA = 0
var ladoB = 0
}
extension Ficha: CustomStringConvertible {
var description: String {
return "f\(numero) \(ladoA)/\(ladoB)"
}
}
var dSet = [Ficha] ()
var rSet = [Int: Ficha] ()
func setDset () {
dSet = []
rSet = [:]
var fj = 0
var x1: Double = 0
var ficha1 : Ficha
var fichanum = 0
for x in 0...6 {
for y in x...6 {
fichanum = fichanum + 1
dSet.append(Ficha.init(numero: fichanum, ladoA: x, ladoB: y))
}
}
dSet.shuffle()
}
setDset()
print (dSet(2))
Using dSet with parenthesis is incorrect, that's the syntax for a function. So the line:
print(dSet(2))
is assuming there's a function that returns something:
func dSet(_ x: Int) -> Something {
return Something
}
To access an item at an index you use the square brackets, so it should be:
print(dSet[2])
Which will print the item at index 2 in the array dSet.
As others have pointed out, you access members of a collection using subscripts, which are invoked via [], not () (which is for regular function calls).
You can simplify this code quite a bit, btw:
import UIKit
struct Ficha {
var numero: Int
var ladoA = 0
var ladoB = 0
}
extension Ficha: CustomStringConvertible {
var description: String {
return "f\(numero) \(ladoA)/\(ladoB)"
}
}
func calculateDset() -> [Ficha] {
let xyPairs = (0...6).flatMap { x in
(x...6).map { y in (x: x, y: y) }
}
return zip(1..., xyPairs)
.map { (fichanum, pair) in
return Ficha(numero: fichanum, ladoA: pair.x, ladoB: pair.y)
}
.shuffled()
}
let dSet = calculateDset()
print(dSet[2])
UIKit already imports Foundation
Make functions return values, don't set them directly.
Don't set initial values to variables, only to immediate overwrite them with something else.
rSet, fj, x1, and ficha1 are unused, delete them.
I'm new to working with swift and have been converting some ios firebase cordova plugin stuff, but ran into a situation that I don't fully understand regarding arrays. I have two snippets of code, one that works and one that doesn't.
Works
var admobTestDevices: [Any] = []
var randomString: String = "abc123"
#objc(FirebasePlugin)
class FirebasePlugin : CDVPlugin {
func something() {
admobTestDevices.append(randomString)
}
}
Doesn't work
#objc(FirebasePlugin)
class FirebasePlugin : CDVPlugin {
var admobTestDevices: [Any] = []
var randomString: String = "abc123"
func something() {
admobTestDevices.append(randomString)
}
}
The one that doesn't work produces Thread 1: EXC_BAD_ACCESS (code=1, address=0x8) as an error. Why does one work and the other doesn't? What is the proper way to have a mutable array as a class property?
For some reason collections become immutable in the subclass in some cases.
You could fix this two ways:
1. override init() initialise the array then call super.init
class FirebasePlugin : CDVPlugin {
var admobTestDevices: [Any] = []
var randomString: String = "abc123"
override init() {
admobTestDevices = [Any]()
super.init()
}
func something() {
admobTestDevices.append(randomString)
}
}
2. Use the lazy modifier so that the array is initialised when first used.
class FirebasePlugin : CDVPlugin {
lazy var admobTestDevices: [Any] = []
var randomString: String = "abc123"
func something() {
admobTestDevices.append(randomString)
}
}
I’m not trying to store an array directly on my CDVPlugin subclass, but I’m storing a struct Queue<T> that has an Array<T> as a top-level member and it was causing the same error that you saw. My solution was to repeat the array initialization in a pluginInitialize method:
struct Queue<T>: ExpressibleByArrayLiteral {
public private(set) var elements: Array<T>
public init() {
self.elements = []
}
public init(arrayLiteral elements: T...) {
self.elements = elements
}
// ...other members...
}
#objc(MyPlugin) class MyPlugin: CDVPlugin {
var requestQueue: Queue<DownloadRequest> = []
override func pluginInitialize() {
requestQueue = Queue<DownloadRequest>()
}
// ...other members...
}
This sort of code would ordinarily not be necessary go in a custom initializer, but the CDVPlugin source warns against subclassing the initializer and says to use pluginInitialize instead. Cordova is clearly doing something unusual here so I’m inclined to trust them on that.
I have a class for a linked list declared like this:
class LinkedNode<T> {
let data: T
var next: LinkedNode<T>?
func traverseList(process: (LinkedNode<T>) -> ()) { ... }
}
What I want to do is extend Array to have an initialiser that converts my LinkedNode class to an array of linked nodes. I tried this:
extension Array where Element == LinkedNode<T> {
init(node: LinkedNode<T>)
{
var result = [LinkedNode<T>]()
traverseList { result.append($0) }
return result
}
}
But that gives errors that T is undeclared. I have tried taking it out and doing other things, but nothing has worked.
I was able to get the same results with a method on the LinkedNode class:
func array() -> [LinkedNode<T>]
{
var result = [LinkedNode<T>]()
traverseList { result.append($0) }
return result
}
But I would prefer an array initialiser since so many other collection types have that initialiser.
You can declare a generic parameter in initializer definition.
extension Array {
init<T>(node: LinkedNode<T>)
where Element == LinkedNode<T>
{
var result = [LinkedNode<T>]()
node.traverseList { result.append($0) }
self = result
}
}
I'm getting a: Cannot invoke 'append' with an argument list of type '([Book])' It works find if I use the += but I don't understand why append() won't work.
struct Book
{
var title:String
var pageCount:Int
}
class Library
{
var onShelfBooks:[Book] = []
var onLoanBooks:[Book] = []
var books:[Book]
{
get
{
return onShelfBooks + onLoanBooks
}
set(newBook)
{
onShelfBooks.append(newBook)
}
}
}
struct Book
{
var title:String
var pageCount:Int
}
class Library
{
var onShelfBooks:[Book] = []
var onLoanBooks:[Book] = []
var books:[Book]
{
get
{
return onShelfBooks + onLoanBooks
}
set(newBook)
{
onShelfBooks.append(newBook[0])
}
}
}
var myLibrary = Library()
var newBook = Book(title: "Swift Development with Cocoa", pageCount: 453)
myLibrary.books = [newBook]
myLibrary.books
Append only allows you to add one object at a time while += allows you to combine an array of objects with another object. When you call append on the setter you are trying to add an array of book objects, or [Book] instead of just a single book object.
If you would like to add [newBook] with append, you can use : of
1- onShelfBooks.append(contentsOf: newBook)
"contentOf" is type of Sequence.
otherwise use of:
2- onShelfBooks += newBook
I want to store structs inside an array, access and change the values of the struct in a for loop.
struct testing {
var value:Int
}
var test1 = testing(value: 6 )
test1.value = 2
// this works with no issue
var test2 = testing(value: 12 )
var testings = [ test1, test2 ]
for test in testings{
test.value = 3
// here I get the error:"Can not assign to 'value' in 'test'"
}
If I change the struct to class it works. Can anyone tell me how I can change the value of the struct.
Besides what said by #MikeS, remember that structs are value types. So in the for loop:
for test in testings {
a copy of an array element is assigned to the test variable. Any change you make on it is restricted to the test variable, without doing any actual change to the array elements. It works for classes because they are reference types, hence the reference and not the value is copied to the test variable.
The proper way to do that is by using a for by index:
for index in 0..<testings.count {
testings[index].value = 15
}
in this case you are accessing (and modifying) the actual struct element and not a copy of it.
Well I am going to update my answer for swift 3 compatibility.
When you are programming many you need to change some values of objects that are inside a collection. In this example we have an array of struct and given a condition we need to change the value of a specific object. This is a very common thing in any development day.
Instead of using an index to determine which object has to be modified I prefer to use an if condition, which IMHO is more common.
import Foundation
struct MyStruct: CustomDebugStringConvertible {
var myValue:Int
var debugDescription: String {
return "struct is \(myValue)"
}
}
let struct1 = MyStruct(myValue: 1)
let struct2 = MyStruct(myValue: 2)
let structArray = [struct1, struct2]
let newStructArray = structArray.map({ (myStruct) -> MyStruct in
// You can check anything like:
if myStruct.myValue == 1 {
var modified = myStruct
modified.myValue = 400
return modified
} else {
return myStruct
}
})
debugPrint(newStructArray)
Notice all the lets, this way of development is safer.
The classes are reference types, it's not needed to make a copy in order to change a value, like it happens with structs. Using the same example with classes:
class MyClass: CustomDebugStringConvertible {
var myValue:Int
init(myValue: Int){
self.myValue = myValue
}
var debugDescription: String {
return "class is \(myValue)"
}
}
let class1 = MyClass(myValue: 1)
let class2 = MyClass(myValue: 2)
let classArray = [class1, class2]
let newClassArray = classArray.map({ (myClass) -> MyClass in
// You can check anything like:
if myClass.myValue == 1 {
myClass.myValue = 400
}
return myClass
})
debugPrint(newClassArray)
To simplify working with value types in arrays you could use following extension (Swift 3):
extension Array {
mutating func modifyForEach(_ body: (_ index: Index, _ element: inout Element) -> ()) {
for index in indices {
modifyElement(atIndex: index) { body(index, &$0) }
}
}
mutating func modifyElement(atIndex index: Index, _ modifyElement: (_ element: inout Element) -> ()) {
var element = self[index]
modifyElement(&element)
self[index] = element
}
}
Example usage:
testings.modifyElement(atIndex: 0) { $0.value = 99 }
testings.modifyForEach { $1.value *= 2 }
testings.modifyForEach { $1.value = $0 }
How to change Array of Structs
for every element:
itemsArray.indices.forEach { itemsArray[$0].someValue = newValue }
for specific element:
itemsArray.indices.filter { itemsArray[$0].propertyToCompare == true }
.forEach { itemsArray[$0].someValue = newValue }
You have enough of good answers. I'll just tackle the question from a more generic angle.
As another example to better understand value types and what it means they get copied:
struct Item {
var value:Int
}
func change (item: Item, with value: Int){
item.value = value // cannot assign to property: 'item' is a 'let' constant
}
That is because item is copied, when it comes in, it is immutable — as a convenience.
Had you made Item a class type then you were able to change its value.
var item2 = item1 // mutable COPY created
item2.value = 10
print(item2.value) // 10
print(item1.value) // 5
This is very tricky answer. I think, You should not do like this:
struct testing {
var value:Int
}
var test1 = testing(value: 6)
var test2 = testing(value: 12)
var ary = [UnsafeMutablePointer<testing>].convertFromArrayLiteral(&test1, &test2)
for p in ary {
p.memory.value = 3
}
if test1.value == test2.value {
println("value: \(test1.value)")
}
For Xcode 6.1, array initialization will be
var ary = [UnsafeMutablePointer<testing>](arrayLiteral: &test1, &test2)
It is possible to use the map function to get this effect - essentially creating a new array
itemsArray = itemsArray.map {
var card = $0
card.isDefault = aCard.token == token
return card
}
I ended up recreating a new array of struct see the example below.
func updateDefaultCreditCard(token: String) {
var updatedArray: [CreditCard] = []
for aCard in self.creditcards {
var card = aCard
card.isDefault = aCard.token == token
updatedArray.append(card)
}
self.creditcards = updatedArray
}
I tried Antonio's answer which seemed quite logical but to my surprise it does not work. Exploring this further I tried the following:
struct testing {
var value:Int
}
var test1 = testing(value: 6 )
var test2 = testing(value: 12 )
var testings = [ test1, test2 ]
var test1b = testings[0]
test1b.value = 13
// I would assume this is same as test1, but it is not test1.value is still 6
// even trying
testings[0].value = 23
// still the value of test1 did not change.
// so I think the only way is to change the whole of test1
test1 = test1b