unable to random pick a element for the array Swift - arrays

#IBOutlet weak var enterName: UITextField!
#IBOutlet weak var presentName: UITextView!
#IBOutlet weak var independceStatue: UITextField!
#IBOutlet weak var driverSelection: UITextField!
var entity : [Entity] = []
var nameList : [String] = []
var period1 = ""
var counting = 0
override func viewDidLoad() {
super.viewDidLoad()
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let request = NSFetchRequest(entityName: "Entity")
var results : [AnyObject]?
do{
results = try context.executeFetchRequest(request)
} catch {
results = nil
}
if results != nil {
self.entity = results as! [Entity]
}
if !entity.isEmpty{
presentName.text = entity.last?.period1Core
}
}
func setValues() {
nameList = [enterName.text!]
}
#IBAction func setName(sender: UIButton) {
setValues()
for item in nameList{
period1 += (item + " ")
}
presentName.text = period1
enterName.text = ""
}
#IBAction func start(sender: UIButton) {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let entity = NSEntityDescription.insertNewObjectForEntityForName("Entity", inManagedObjectContext: context) as! Entity
entity.period1Core = presentName.text
do {
try context.save()
print("Item Saved")
} catch _ {
print("Saved Failed")
}
**Problem ->** let randomIndex = Int(arc4random_uniform(UInt32(nameList.count)))
driverSelection.text! = nameList[randomIndex]
print(randomIndex)
}
I was trying to randomly pick an element out from the array name nameList, but when I run the program and print the randomIndex, after first time I press the button it will always return last element in the array.
If I exit the simulator and run it again, when I press the button it will return me fatal error Array Index is out of range. Is there somethings wrong with my code, why am I not able to make it randomly select an element from my array?

Your setValues() function always replaces the entire array with the last name entered. That's why it seems to return the last value.
you probably meant to use nameList.append(enterName.text!) in it.
The crash upon starting may occur because nameList has not yet received a name and arc4random_uniform is being called with a parameter value of zero

Related

Swift - User Defaults not loading array of strings when app is launched

So I have an app for a Midwestern car game where you count cows when you're driving and when you see a cemetery you lose half your cows. Whenever someone sees a cemetery, I have an emoji appear as an appended array of string, so they keep adding up. My problem is I can save the array to user defaults and it will print it correctly, but whenever I relaunch the app, the array goes back to a blank array of strings. So I know the data is saved correctly, just not loading when the app launches.
class ViewController: UIViewController {
#IBOutlet weak var playerOneNameText: UITextField!
#IBOutlet weak var numberOfCowsPlayerOne: UILabel!
#IBOutlet weak var playerOneCows: UILabel!
#IBOutlet weak var playerOneCemeteries: UILabel!
let userDefaults = UserDefaults.standard
var cemeteryEmoji: [String] = UserDefaults.standard.object(forKey: "CemeteryEmoji")! as? [String] ?? []
It will also strangely load the correct array in the field for display, but will start over any time a new cemetery is added:
override func viewDidLoad() {
super.viewDidLoad()
if userDefaults.value(forKey: "CemeteryEmoji") != nil{
playerOneCemeteries.text = "\(UserDefaults.standard.object(forKey: "CemeteryEmoji")!)"
print(cemeteryEmoji)
}else {
playerOneCemeteries.text = ""
}
}
And here's the function for all the cemetery data:
#IBAction func playerOneCemetery(_ sender: UIButton) {
let cemeteryCows = UserDefaults.standard.integer(forKey: "TotalCows") / 2
self.userDefaults.set(cemeteryCows, forKey: "TotalCows")
print(cemeteryCows)
self.numberOfCowsPlayerOne.text = "\(self.userDefaults.string(forKey: "TotalCows")!) cows"
addCemeteryEmoji()
print(UserDefaults.standard.object(forKey: "CemeteryEmoji")!)
func addCemeteryEmoji() {
cemeteryEmoji.append("🪦")
print(cemeteryEmoji)
self.playerOneCemeteries.text = "\(cemeteryEmoji.joined())"
userDefaults.set(cemeteryEmoji.joined(), forKey: "CemeteryEmoji")
}
}
So I'm not sure if it's an issue simply when the app loads or if I need to save it a different way (although as I said, that works perfectly fine with all the print statements). Any help would be great.
The error occurs because you join the array right before saving it which creates a single string.
And when you relaunch the app object(forKey: "CemeteryEmoji")! as? [String] fails.
I highly recommend to name the array more meaningful and use the dedicated API array(forKey:).
Name the array in plural form and declare an empty array
var cemeteryEmojis = [String]()
In viewDidLoad load the array from UserDefaults
override func viewDidLoad() {
super.viewDidLoad()
if let emojis = userDefaults.array(forKey: "CemeteryEmoji") as? [String] {
playerOneCemeteries.text = "\(emojis.joined())"
cemeteryEmojis = emojis
print(cemeteryEmojis)
} else {
playerOneCemeteries.text = ""
}
}
And delete joined() in the set line of addCemeteryEmoji
func addCemeteryEmoji() {
cemeteryEmojis.append("🪦")
print(cemeteryEmojis)
self.playerOneCemeteries.text = "\(cemeteryEmojis.joined())"
userDefaults.set(cemeteryEmojis, forKey: "CemeteryEmoji")
}

Array value shows all information of the coreData value rather than just the value

I'm hoping someone can help me understand how to get the value from an array rather than all system information about the array as shown via screen shot below.
I would instead prefer just "test" to show to prove that CoreData saved and returned the value.
Here is the code:
import UIKit
import CoreData
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newItem = Item(context: context)
var textIn = ""
var textOut = ""
var itemArray = [] as Array
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var dataIn: UITextField!
#IBAction func save(_ sender: Any) {
newItem.title = dataIn.text
saveItems()
}
#IBOutlet weak var textLabel: UILabel!
#IBAction func showButton(_ sender: Any) {
loadItems()
}
func saveItems() {
do {
try context.save()
print("Saved!")
} catch {
print("Error saving context \(error)")
}
}
func loadItems() {
let request : NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request) as [Any]
for item in itemArray {
print(item.self)
textLabel.text = ("Value: \(item.self)")
}
} catch {
print("Error fetching data from context \(error)")
}
}
}
Thanks!
Rather than the worst type [Any] use the best type [Item]
var itemArray = [Item]()
Then remove the pointless type cast in loadItems to be able to use the title attribute
func loadItems() {
let request : NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request)
for item in itemArray {
print(item.title)
textLabel.text = ("Value:", item.title)
}
} catch {
print("Error fetching data from context \(error)")
}
}
Consider that after the loop the label will display always the title of the last item in the array.

Look through all records for a specific attribute and see the highest value

Ok, so I have an app that is designed for roleplaying. I have a guide that guides the user to creating the character. So the first thing the user has to do is put the character number. So I want it to search all the records for the attribute I have called characternumber and see what the largest number is.
Example: Lets say I have 5 characters. with character numbers 1,2,3,4,5. I want to cycle through all the records and see that 5 is the biggest number than automatically place a 6 in the character number text field.
This is what I have so far:
#IBOutlet var societyNumberTxt: UITextField!
#IBOutlet var characterNumberTxt: UITextField!
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var characters: [NSManagedObject] = []
var societyNum: [NSManagedObject] = []
var charNum: [String] = []
override func viewDidLoad()
{
super.viewDidLoad()
//1
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
//2
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Characters")
//3
do {
societyNum = try managedContext.fetch(fetchRequest)
let entityDescription = NSEntityDescription.entity(forEntityName: "Characters", in: managedObjectContext)
let request: NSFetchRequest<Characters> = Characters.fetchRequest()
request.entity = entityDescription
var results = try managedObjectContext.fetch(request as! NSFetchRequest<NSFetchRequestResult>)
if societyNum.count > 0
{
let match = results[0] as! NSManagedObject
societyNumberTxt.text = (match.value(forKey: "societynumber") as? String)!
print(match)
if (match.value(forKey: "characternumber") != nil)
{
self.charNum = match.value(forKey: "characternumber") as! [String]
print(self.charNum)
}
else
{
print("empty array")
characterNumberTxt.text = "1"
}
}
else
{
societyNumberTxt.placeholder = "Society # not set"
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
I am not sure how to cycle through every record and check the attribute and place in the array. I have tried something like this:
var i = 0
for i in results
{
var match = results[i] as? NSManagedObject
charNum[i] = match
}
I get the error:
cannot subscript a value of type '[Any]' with an index of type 'Any'
Now to test my code for the if statement:
if (match.value(forKey: "characternumber") != nil)
{
self.charNum = match.value(forKey: "characternumber") as! [String]
print(self.charNum)
}
It returned and error:
Could not cast value of type 'NSTaggedPointerString' (0x108578d10) to 'NSArray' (0x108578dd8).
Am I even on the right past?
Adjust your fetch request with a SortDescriptor instead of finding the highest characterNumber manually:
...
//2
// get all characters ...
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Characters")
// ... sorted by characternumber in acending order
let sortDescriptor = NSSortDescriptor(key: "characternumber", ascending: true)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
//3
do {
let characters = try managedContext.fetch(fetchRequest) as! [Characters]
if let highestCharacterNumber = characters.last?.characternumber {
characterNumberTxt.text = String(highestCharacterNumber + 1) // assuming characternumber is of type Int
} else {
characterNumberTxt.text = "1"
}
} ...

Wrong order in string array

I have this code that passes the entries from textfield and adds them to a string array in another view controller. The problem is, the order is not correct.
This is my code:
//Textfields
#IBOutlet weak var text1: UITextField!
#IBOutlet weak var text2: UITextField!
#IBOutlet weak var text3: UITextField!
#IBOutlet weak var text4: UITextField!
#IBOutlet weak var text5: UITextField!
#IBOutlet weak var text6: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Delegates each textfield
text1.delegate = self
text2.delegate = self
text3.delegate = self
text4.delegate = self
text5.delegate = self
text6.delegate = self
//Tags each textfield
text1.tag = 1
text2.tag = 2
text3.tag = 3
text4.tag = 4
text5.tag = 5
text6.tag = 6
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
let nextTag: NSInteger = textField.tag + 1;
if let nextResponder: UIResponder! = textField.superview!.viewWithTag(nextTag){
nextResponder.becomeFirstResponder()
}
else {
textField.resignFirstResponder()
}
return false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as! secondView
if segue.identifier == segueID {
//Adds the textfield entries to the string array on the second view controller
destination.stringArray = view.subviews.flatMap { ($0 as? UITextField)?.text }
destination.delegate = self
}
}
But I have no idea what is wrong with my code, why would it send the incorrect order to my array. My array looks like this:
["q", "w", "e", "t", "y", "r"]
when it should be...
["q", "w", "e", "r", "t", "y"]
This is just random letters I chose, the entries could be anything really. But the order is important. Could someone check my code, see where did I go wrong? Thank you in advance.
You need to sort the UITextField(s) you are retrieving
So replace this
destination.stringArray = view.subviews.flatMap { ($0 as? UITextField)?.text }
with this
destination.stringArray = view
.subviews
.flatMap { $0 as? UITextField }
.sort { $0.0.tag < $0.1.tag }
.flatMap { $0.text }
Alternatively, go from the tag to the field instead of the field to the tag:
destination.stringArray = (1...6).flatMap({ (view.viewWithTag($0) as? UITextField).text})

Type '___' has no member 'array'

I am working on this quote app, and I keep running into two errors that just don't want to cooperate with me. It says "Type 'businessQuote' has no member ('array'/'dict')". In the following screen shot, you will see the error on the line. The whole point is to get the app to show a random quote in the text fields provided. Could you please help me? Thank you in advance.
Code with the error
My goal is to get "ImportList" to work
'ImportList' Swift file
If there is another question like this that I have overlooked, I would appreciate it if you could link me to it. But I just really need an answer. Thank you again.
Here's the code with the error:
import Foundation
import UIKit
import Social
class businessQuote: UIViewController {
//============================//
//********** Outlets *********//
//============================//
let utility = Utility()
#IBOutlet weak var quoteDisplay: UILabel!
#IBOutlet weak var authorDisplay: UILabel!
#IBOutlet weak var quoteBackground: UIImageView! //GET BACK TO THIS
//============================//
//********** General *********//
//============================//
let date = NSDate()
var Author: String = ""
var Quote: String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Checks if time is greater then 3pm to change background
let currentTime = utility.currentTime()
if (currentTime >= 15 ) {
quoteBackground.image = UIImage(named: "quote_background.png")
} else {
quoteBackground.image = UIImage(named:"morning_quote_background.png")
}
}
//============================//
//********* New Quote ********//
//============================//
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// Generates Random Number
func randomNumber(arrayLength: Int) -> Int {
let unsignedArrayCount = UInt32(arrayLength)
let unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
let randomNumber = Int(unsignedRandomNumber)
return randomNumber
}
// Importing Quotes plist File
let businessQuotes = ImportList(FileName: "BusinessList")
// Selects Quote
let chosenQuote: String = businessQuote.array[randomNumber(businessQuote
.count())] as! String
let chosenAuthor = businessQuote.dict[chosenQuote]! as String
// Assigns Quote & Author to IBOutlet
Author = chosenAuthor
Quote = chosenQuote
quoteDisplay.text = Quote
authorDisplay.text = Author.uppercaseString
}
}
This is the code with the 'array' and 'dict'
import Foundation
struct ImportList {
let path: String
init(FileName: String) {
self.path = NSBundle.mainBundle().pathForResource("\(FileName)", ofType: "plist")!
}
var dict: Dictionary<String, String> {
return NSDictionary(contentsOfFile: path)! as! Dictionary
}
var array: Array<AnyObject> {
return [String](arrayLiteral: String(dict.keys) { $0 as AnyObject as! String })
}
func count() -> Int {
return array.count
}
}
Thank you!
You have declared variable businessQuotes as:
// Importing Quotes plist File
let businessQuotes = ImportList(FileName: "BusinessList")
But using businessQuote instead, see you are missing "s" at the end. Spelling mistake. Following lines should be:
// Selects Quote
let chosenQuote: String = businessQuotes.array[randomNumber(businessQuotes
.count())] as! String
let chosenAuthor = businessQuotes.dict[chosenQuote]! as String

Resources