how to merge two arrays into a struct - arrays

What I want my swift code to do is take the two arrays initilized in view controller and then move them into the struct added. I want to do the transfer in view did load. I dont know what I am doing so I put some code that I thought might be helpful but right now my code is not compiling in view did load.
import UIKit
class ViewController: UIViewController {
var emptyA = [Int]()
var emptyb = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
added.init(emptyA, emptyb)
}
}
struct added {
var arrayOne = //emptyA
var arrayTwo = //emptyb
}

You need to declare your struct like this:
struct Added {
var arrayOne: [Int]
var arrayTwo: [UIImage]
}
Then to declare an instance you would do this:
let a = Added(arrayOne: emptyA, arrayTwo: emptyb)
Also, it's typically good form to start the name of your structs with a capital letter.

Related

Object array cannot display all variables using SwiftUI?

import UIKit
import SwiftUI
var str = "Hello, playground"
struct FianceItem: Identifiable,Codable {
public var id: UUID = UUID()
public var name: String
public var childs:[FianceItem] = []
}
var root=FianceItem(name: "root")
var childA=FianceItem(name: "childA")
root.childs.append(childA)
var childB=FianceItem(name: "childB")
childA.childs.append(childB)
print(root)
struct is a value type. When you assign it to another variable, its value is copied.
So order matters in this case.
This line is creating a copy of childA and putting it into the array of root.
root.childs.append(childA)
When you edit the original, the copy does not have childB.
Either reorder the code like Raja Kishan's answer or use class instead of struct.
Change your sequence
let contentView = DeveloperView()
var root=FianceItem(name: "root")
var childA=FianceItem(name: "childA")
var childB=FianceItem(name: "childB")
childA.childs.append(childB)
root.childs.append(childA)
print(root)

Updating element values of an array in swift

I have a lot of experience working with Matlab, but I only recently started programming in Swift 4. My current project involves building a questionnaire. I have used the ‘drag and drop’ feature in Xcode to produce an #IBAction function for a button in storyboard, which can then lead to pressed button changing its appearance. This functionality is contained within the ButtonResponse class in the code snippet below:
struct ResponseProfile {
var responseArray: Array<String>
init(responseArray: Array<String>) {
self.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
}
mutating func updateArray(_ anArray: Array<String>) -> (Array<String>) {
responseArray = anArray
return responseArray
}
}
class ButtonResponse: UIButton {
var responseVariables: ResponseProfile
var checkedImage = UIImage(named: "checkedResponseBox")! as UIImage
var uncheckedImage = UIImage(named: "uncheckedResponseBox")! as UIImage
required init?(coder aDecoder: NSCoder) {
self.responseVariables = ResponseProfile(
responseArray: []
)
super.init(coder: aDecoder)
}
#IBAction func checkboxTapped(_ sender: UIButton) {
switch sender.accessibilityIdentifier {
case "excellent":
let oldResponseStatus = responseVariables.responseArray[0]
if oldResponseStatus == "unchecked"{
sender.setImage(checkedImage, for: UIControlState.normal)
let oldResponsePresence = responseVariables.responseArray.contains("checked")
if oldResponsePresence == true {
responseVariables.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
}
responseVariables.responseArray[0] = "checked"
} else if oldResponseStatus == "checked" {
sender.setImage(uncheckedImage, for: UIControlState.normal)
responseVariables.responseArray[0] = "unchecked"
}
case "veryGood":
let oldResponseStatus = responseVariables.responseArray[1]
if oldResponseStatus == "unchecked" {
sender.setImage(checkedImage, for: UIControlState.normal)
let oldResponsePresence = responseVariables.responseArray.contains("checked")
if oldResponsePresence == true {
responseVariables.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
}
responseVariables.responseArray[1] = "checked"
} else if oldResponseStatus == "checked" {
sender.setImage(uncheckedImage, for: UIControlState.normal)
responseVariables.responseArray[1] = "unchecked"
}
default: break
}
}
}
I imagined that I could use an array to internally represent the state of the buttons in the user interface (this would be the ‘responseArray’ variable). By changing elements within responseArray following a button press, I thought I could keep track which buttons were pressed and ensure that no more than one button at a time was checked. I incorrectly thought responseArray would be updated, but this is not the case. The array always reverts to its initiation state.
N.B. responseArray contains seven elements because there are seven response options. So far, I have attempted to program only two of the response options: “excellent” and “veryGood”.
In attempting to find a solution, I attempted to simplify the above code in playground:
import UIKit
struct ResponseProfile {
var responseArray: Array<String>
init(responseArray: Array<String>) {
self.responseArray = ["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
}
mutating func updateArray(input anArray: Array<String>) -> (Array<String>) {
responseArray = anArray
return responseArray
}
}
class ButtonResponse {
var responseVariables: ResponseProfile
init(){
self.responseVariables = ResponseProfile(responseArray: [])
}
var responseA = ResponseProfile(responseArray: [])
}
var responseOne = ResponseProfile(responseArray: [])
responseOne.responseArray[0] = "checked" //user performs action resulting in first element being changed from a starting value of "unchecked" to "checked"
responseOne.updateArray(input: responseOne.responseArray)
var responseTwo = ResponseProfile(responseArray:[])
responseTwo.responseArray //responseArray revert to initialization values. How can I keep changes to the responseArray?
How can I update responseArray within the ResponseProfile structure without having to create a new variable to record every change? Is this the problem I should be looking at or is there, on a more general level, a better strategy that I should be taking?
I am surprised that I struggled this much to deal with this issue. I thought the answer would be clear if I read the relevant parts of the documentation and studied some example code. All the example code I found was too simplistic and focused on just one iteration of updating the array.
Any comments or suggestions would be much appreciated!
Looking at your playground code, I found that you are passing a blank [] array to argument of ResponseProfile struct during init. and it is always initialising your responseArray.
If you want to pass the things by reference, you can change Response profile to class
and there you can achieve the similar functionalities and use inout parameter to keep the same array without using the function updateArray.
The example I am showing here is for the class and objects of class can be pass by reference. thus keep your previous changes.
var responseTwo = ResponseProfile(responseArray:[])
If you wants to keep the old response, you can pass that array as an argument
var responseTwo = ResponseProfile(responseArray:responseOne.responseArray)
OR
var responseTwo = responseOne
Will keep the responseArray.
You can read more about it, at official blog
Also you can this post with more insight for the case.
Hope it helps.
Thanks for your response Bhavin. By passing responseArray by reference (as Bhavin suggests) to the necessary class (which has turned out to be the ButtonResponse class rather than ResponseProfile), I can give responseArray an initial value. I then use the buttonPress function to update responseArray. See below:
class ButtonResponse: Responses {
var responseArray: [String]
init (responseArray: [String]) {
self.responseArray = responseArray
}
func buttonPress(inputString: String, targetIndex: Int) -> [String] {
//need guard statement to block function when targetIndex > number of elements in responseArray
responseArray[targetIndex] = inputString
return responseArray
}
}
let initiateResponseArray =
["unchecked","unchecked","unchecked","unchecked","unchecked","unchecked","unchecked"]
var doPress = ButtonResponse(responseArray: initiateResponseArray)
doPress.buttonPress(inputString: "checked", targetIndex: 0)
var getPressInfo1 = doPress.responseArray
print(getPressInfo1)
//prints: ["checked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]
doPress.buttonPress(inputString: "checked", targetIndex: 1)
var getPressInfo2 = doPress.responseArray
print(getPressInfo2)
//prints: ["checked", "checked", "unchecked", "unchecked", "unchecked", "unchecked", "unchecked"]
I am still unsure how to implement this solution in the project I am working on. I will create a separate question for this because it seems to raise different issues.

EXC_BAD_ACCESS when appending to array class property

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.

Storing var in array

Do I have to set the array to a specific type so that it will store the images or is it something else. The images are stored in the Images.xcassets
class GameScene: SKScene {
var blueTexture = SKTexture(imageNamed: "BlueBall.png")
var greenTexture = SKTexture(imageNamed: "GreenBall.png")
var redTexture = SKTexture(imageNamed: "redTexture.png")
var array = [blueTexture, greenTexture, redTexture]
//error: GameScene does not have a member called blueTexture
//this goes for the other textures as well
This is because you can't access other properties during initialization, so you could replace you current code with this:
var blueTexture = SKTexture(imageNamed: "BlueBall.png")
var greenTexture = SKTexture(imageNamed: "GreenBall.png")
var blueTexture = SKTexture(imageNamed: "BlueBall.png")
var array:[SKTexture]!
override func didMoveToView(view: SKView)
{
array = [blueTexture,greenTexture,blueTexture]
}
Also, you made two blueTextures.

Pass Full Array between view controllers in swift

I am trying to pass a full array between view controllers but cannot figure out the missing piece.
In view controller one I have:
protocol ExclusionsViewViewControllerDelegate{
func ExcUpperDidFinish(controller:ExclusionsView)
func ExcLowerDidFinish(controller:ExclusionsView)
}
class ExclusionsView: UIViewController, UITableViewDataSource, UITableViewDelegate {
var delegate:ExclusionsViewViewControllerDelegate? = nil
var ExcLowerArray:[Int]=[]
var ExcUpperArray:[Int]=[]
#IBOutlet var ExcLowerText: UITextField!
#IBOutlet var ExcUpperText: UITextField!
#IBOutlet var ExcFreqTable: UITableView!
#IBAction func BackButton(sender: AnyObject) {
if (delegate != nil){
delegate!.ExcUpperDidFinish(self, Array: ExcUpperArray)
delegate!.ExcLowerDidFinish(self, Array: ExcLowerArray)
}
dismissViewControllerAnimated(true,completion:nil)
}
In View controller two I have:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, PreferencesViewControllerDelegate, ExclusionsViewViewControllerDelegate {
var ExcUpperFreqArray:[Int]=[]
var ExcLowerFreqArray:[Int]=[]
override func viewDidLoad() {
super.viewDidLoad()
}
func ExcLowerDidFinish(controller: ExclusionsView, Array:[Int]) {
ExcLowerFreqArray = Array
controller.navigationController?.popViewControllerAnimated(true)
}
func ExcUpperDidFinish(controller: ExclusionsView, Array:[Int]) {
ExcUpperFreqArray = Array
controller.navigationController?.popViewControllerAnimated(true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "pushExclusions"{
let zc = segue.destinationViewController as ExclusionsView
zc.ExcLowerArray = ExcLowerFreqArray
zc.ExcUpperArray = ExcUpperFreqArray
}
}
I cannot figure out how to correctly reference the array. I am trying to create the array ExcLowerArray in view controller one, and when I change view it will copy all data to the array ExcLowerFreqArray in the second view controller, so that I can reference it in that view controller. At the moment though I get an error on these two lines:
delegate!.ExcLowerDidFinish(self, Array: ExcLowerArray)
func ExcLowerDidFinish(controller: ExclusionsView, Array:[Int]) {
Swift arrays are value types, and as such they are passed not by reference but by value, which means a copy is created when an array is passed to a function, assigned to a variable, etc.
In order to pass an array (and more generally any value type) to a function by reference, you can use the inout modifier in the function declaration, and use the reference operator & when passing the argument to the function. In your case:
func ExcLowerDidFinish(controller: String, inout Array:[Int])
and:
delegate!.ExcLowerDidFinish(self, Array: &ExcUpperArray)
Off topic: note that by convention in swift functions/methods and variables/parameters names start with lowercase, whereas types (classes, structs, etc.) start with uppercase. Your code may be hard to read by other Swift developers

Resources