Segue textfields to a string array - arrays

I'm doing an app using swift that takes the entries in 6 text fields and passes them through a segue into an empty string array on a second view controller. How do I do that?
This is my code, is the basics, but I'm not sure how I can send the information through.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as! secondView
if segue.identifier == segueID {
destination.stringArray = ?
}
}
The array on my second view controller is this:
var stringArray = [String]()

The shortest way:
destination.stringArray = view.subviews.flatMap { ($0 as? UITextField)?.text }

Are your 6 textfields in an IBOutletCollection (in other words, an array of textfields) or are they each their own IBOutlet (textfield)? Either way, your question comes down to putting all of their text values in an array, which can be done like this if they're in an IBOutletCollection:
destination.stringArray = myTextFieldCollection.flatMap { $0.text }
Or, if they're not in an array:
destination.stringArray = [myTextField1, myTextField2, ...,
myTextField6].flatMap { $0.text }
I'm using flatMap in these because UITextField.text is an optional String?, so they need to be unwrapped to String, which flatMap safely does.

Related

How to pass value from 2d array with prepareForSegue

I have a array like this in a tableView:
var array: [[String]] = [["Apples", "Bananas", "Oranges"], ["Round", "Curved", "Round"]]
I would like to pass on the name of the cell when the cell is pressed. With a standard array I would do this:
let InfoSegueIdentifier = "ToInfoSegue"
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == InfoSegueIdentifier
{
let destination = segue.destination as! InfoViewController
let arrayIndex = tableView.indexPathForSelectedRow?.row
destination.name = nameArray[arrayIndex!]
}
}
And in the next ViewController (InfoViewController)
var name = String()
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = name
}
Error: "Cannot assign value of type '[String]' to type 'String'"
Change this part of code
if segue.identifier == InfoSegueIdentifier
{
let destination = segue.destination as! InfoViewController
let arrayIndex = tableView.indexPathForSelectedRow?.row
destination.name = nameArray[arrayIndex!]
}
To
if segue.identifier == InfoSegueIdentifier
{
let destination = segue.destination as! InfoViewController
let arrayIndexRow = tableView.indexPathForSelectedRow?.row
let arrayIndexSection = tableView.indexPathForSelectedRow?.section
destination.name = nameArray[arrayIndexSection!][arrayIndexRow!]
}
Try and share the results.
Reason For crash: In your first viewController you have [[String]] which is the datasource for your section. Now, when you try to get the object from this array it will returns you [String] and in your destination viewController you have the object of type String. and while assigning [String] to String it cause the crash with type mismatch. So, what above code does is, it will take first [String] from the arrayIndexSection and then the String from arrayIndexRow and thus pass a String object to destination.
Hope it clears.
You are getting this error because you are passing an array to second view controller and there is a variable of type string. So, replace this method like this.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == InfoSegueIdentifier
{
let destination = segue.destination as! InfoViewController
if let indexPath = tableView.indexPathForSelectedRow{
destination.name = nameArray[indexPath.section][indexPath.row]
}
}
}

Saving a generated word to an array/list of words when a button is pressed

I bet this is a pretty simple question for most of you so I'll be quick. Essentially my Swift app generates a random word, and I want the users to be able to select buttons labeled 1 2 and 3, and that word is then saved to that particular number in an array. Later on (including after when the app has been closed etc.) the user can view all the words they have assigned a number to. I know it involves creating a new class and placing the respective arrays there but I really have no idea where to start, so any help is appreciated. Sorry if this isn't as clear as you'd like, as you can tell I'm pretty new to Swift/programming. As of right now, all I have related to this part of the app is the buttons:
var chosenNumber : String = ""
#IBAction func chosenOne(_ sender: Any) {
chosenDifficulty = "one"
}
#IBAction func chosenTwo(_ sender: Any) {
chosenNumber = "two"
}
#IBAction func chosenThree(_ sender: Any) {
chosenNumber = "three"
}
thanks
Create a computedProperty In your ViewController that saves if there's a new value and return the saved value when you access it anywhere in your viewController:
var savedWords: [String: Any]? {
set{
guard let value = newValue else {
UserDefaults.standard.removeObject(forKey: "SavedWords")
UserDefaults.standard.synchronize()
return
}
UserDefaults.standard.set(value, forKey: "SavedWords")
UserDefaults.standard.synchronize()
}
get{
return UserDefaults.standard.string(forKey: "SavedWords") as? [String: Any]
}
}
and a dictionary that contains a key-value pair of current words that you're going to add/delete into
var currentWords: [String: Any]? = ["button1": "one","button2": "two","button3": "three"]
Now, whenever your button is clicked you can add your particular word to currentWords dictionary in association with the currentButton key by:
currentWords["button1"] = /*selectedValue from button*/
After assigning if you want to save those currentWords just do
self.savedWords = currentWords
If you want to retrieve savedWords and assign it to currentWords, you can simply do:
self.currentWords = savedWords

Permanent Data with Prepare For Segue

I am currently trying to use Permanent Data and Prepare For Segue together. This is what I have so far: (VC1)
override func viewDidAppear(_ animated: Bool) {
let itemsObject = UserDefaults.standard.object(forKey: "items")
if let tempItems = itemsObject as? [String] {
items = tempItems
}
(VC2):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toSecondViewController" {
let itemsObject = UserDefaults.standard.object(forKey: "items")
var items:[String]
if let tempItems = itemsObject as? [String] {
items = tempItems
items.append(textField.text!)
print(items)
} else {
items = [textField.text!]
}
UserDefaults.standard.set(items, forKey: "items")
}
}
I am trying to add an item to an array on VC2. Then I want to transfer the array to VC1 whilst storing it permanently. I am using Xcode 8.0 and Swift 3.0.
Its the other way around; when your source view controller initiates a segue from either a storyboard or performSegue, the source view controller's prepareForSegue method gets invoked. With in that method you should determine the type of view controller you are segueing to and set the properties accordingly. Note that you don't really need the identifier unless you have more than one segue to the same destination in which case its sometimes useful to know which one is being invoked.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let notificationsViewController = segue.destination as? NotificationsViewController {
NotificationsViewController.notification = notification
}
}
Your question only explains.how to pass and store data permanently. But, you haven't mentioned about where you want to save data. I presume,you using tableView to store data and retrieving it.
In AppDelegate applicationDidFinishLaunching register an empty array as default value for the key "NewArray".
let defaultValues = ["NewArray": [String]()]
UserDefaults.standard.register(defaults: defaultValues)
In Second VC define newArray (variable names are supposed to start with a lowercase letter) also as empty String array
var newArray = [String]()
In viewDidLoad retrieve the array from user defaults, append the new item, save the array back to user defaults and reload the table view
override func viewDidLoad() {
super.viewDidLoad()
let defaults = UserDefaults.standard
newArray = defaults.array(forKey: "NewArray") as! [String]
newArray.append(newItem) //newItem is the data.Which you passing from First VC
defaults.set(newArray, forKey: "NewArray")
self.tableView?.reloadData()
}
and you don't need to use segue on your second VC unless you passing data from it...

Why can't I pass an array to a vararg in Swift?

I have this function:
func doStuff(stuff: Int...) {
print(stuff)
}
and I call it like this:
let array = [1, 2, 3]
doStuff(array)
And it does not compile!
I mean, this makes no sense, right? The function is supposed to accept a list of things, and I am giving it a list of things. How come this doesn't work?
Here's some background info (you can skip it)
I have this NSManagedObject subclass:
class Entry: NSManagedObject {
override init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?) {
// irrelevent
}
convenience init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext, title: String, content: String, date: NSDate) {
// irrelevent
}
}
extension Entry {
#NSManaged var content: String?
#NSManaged var date: NSDate?
#NSManaged var title: String?
}
In one of my view controllers, I fetch all the Entrys in viewDidLoad and I stored the fetched stuff in a variable called anyObjs which is of type [AnyObject]
I want to turn this [AnyObject] to a [NSDate: Entry], where the keys are the values' date property. I want it this way in order to easily access an Entry using an NSDate.
So I tried the following:
let literal = anyObjs!.map { (($0 as! Entry).date!, $0 as! Entry) }
entries = [NSDate: Entry](dictionaryLiteral: literal)
And I found out that I can't pass a [(NSDate, Entry)] to (NSDate, Entry)...!
"That's easy" you might say, "just pass all the elements in the array as varargs using the subscript!"
doStuff(array[0], array[1], array[2])
But this doesn't work if I don't know how many items there are.
Another workaround that doesn't work is to create a function that accepts an array:
func doStuff(array: [Int]) {
print(array)
}
This doesn't work either because if I don't know the exact implementation of the function, I cannot rewrite it in the new function.
What can I do?
You are right! There ought to be a method for getting a dictionary from an array of tuples.
extension Dictionary {
init(tuples: [Element]) {
self.init()
for (key, value) in tuples {
self.updateValue(value, forKey: key)
}
}
}
OK, now that's done, let's see.
let tuples = anyObjs!.map { (($0 as! Entry).date!, $0 as! Entry) }
let entries = [NSDate: Entry](tuples: tuples)
Or combine the two lines
let entries = [NSDate: Entry](tuples: anyObjs!.map { (($0 as! Entry).date!, $0 as! Entry) })

prepare for segue...with pointers?

var routes:[PFObject] = [PFObject]()
func getRoutes() {
let query = PFQuery(className: "PoolRoute")
query.includeKey("selectedCustomer")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects as? [PFObject] {
self.routes = objects
self.tableView.reloadData()
these objects have a column named "selectedCustomer" that is full of pointer objects.....I would like to segue to another tableview controller and display the pointer objects from the selected cell...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue == "toRoutesDetailVC" {
let nav = segue.destinationViewController as! PoolRouteDetailVC
if let indexPath = self.tableView?.indexPathForSelectedRow {
nav.currentObject = (self.routes[indexPath.row]["selectedCustomer"] as [PFObject])
// '() -> NSIndexPath?' does not have a member named 'row'
//i guess its not the right syntax...not exactly sure how to write the code to get it to send to the array to the detailViewController. thanks in advance!

Resources