Error Saving Text Views in NSUserDefault - swift

I have 6 textViews and one button to save the text wrote in them.
The problem is that the button just save until the forth TextView, fifth and sixth are not saved properly , they just copy the text in third and fourth textviews
Example
First text view - Correctly saved
Second text view - Correctly saved
Third text view - Correctly saved
Fourth text view - Correctly saved
Fifth text view - Its a copy of the text on third text view
Sixth text view - Its a copy of the text on fourth text view
Save button.
It seems all code are ok and all of the text views are linked successfully , but the last two textViews still fail.
My code here:
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var labelUno: UILabel!
#IBOutlet weak var labelDos: UILabel!
#IBOutlet weak var primerTextView: UITextView!
#IBOutlet weak var segundoTextView: UITextView!
#IBOutlet weak var tercerTextView: UITextView!
#IBOutlet weak var cuartoTextView: UITextView!
#IBOutlet weak var quintoTextView: UITextView!
#IBOutlet weak var sextoTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.contentSize.height = 2000
labelUno.text = "¿Qué significa el éxito para ti? , ¿significa ser millonario , ser famoso , contribuir de alguna manera a ayudar a muchas personas, ser un buen padre o madre de familia, ser el mejor en tu profesión??"
primerTextView.layer.borderWidth = 0.8
primerTextView.layer.borderColor = UIColor.blackColor().CGColor
primerTextView.layer.cornerRadius = 8.0
segundoTextView.layer.borderWidth = 0.8
segundoTextView.layer.borderColor = UIColor.blackColor().CGColor
segundoTextView.layer.cornerRadius = 8.0
tercerTextView.layer.borderWidth = 0.8
tercerTextView.layer.borderColor = UIColor.blackColor().CGColor
tercerTextView.layer.cornerRadius = 8.0
cuartoTextView.layer.borderWidth = 0.8
cuartoTextView.layer.borderColor = UIColor.blackColor().CGColor
cuartoTextView.layer.cornerRadius = 8.0
quintoTextView.layer.borderWidth = 0.8
quintoTextView.layer.borderColor = UIColor.blackColor().CGColor
quintoTextView.layer.cornerRadius = 8.0
sextoTextView.layer.borderWidth = 0.8
sextoTextView.layer.borderColor = UIColor.blackColor().CGColor
sextoTextView.layer.cornerRadius = 8.0
//Save Button
let stringKey = NSUserDefaults.standardUserDefaults()
segundoTextView.text = stringKey.stringForKey("key")
primerTextView.text = stringKey.stringForKey("key2")
tercerTextView.text = stringKey.stringForKey("key3")
cuartoTextView.text = stringKey.stringForKey("key4")
quintoTextView.text = stringKey.stringForKey("key5")
sextoTextView.text = stringKey.stringForKey("key6")
//Hide keyboard
//Hide keyboard with touching anywhere
var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DismissKeyboard")
view.addGestureRecognizer(tap)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
#IBAction func saveButton(sender: AnyObject) {
let myText = segundoTextView.text
let myText2 = primerTextView.text
let myText3 = tercerTextView.text
let myText4 = cuartoTextView.text
let myText5 = quintoTextView.text
let myText6 = sextoTextView.text
NSUserDefaults.standardUserDefaults().setObject(myText, forKey: "key2")
NSUserDefaults.standardUserDefaults().setObject(myText2, forKey: "key")
NSUserDefaults.standardUserDefaults().setObject(myText3, forKey: "key3")
NSUserDefaults.standardUserDefaults().setObject(myText4, forKey: "key4")
NSUserDefaults.standardUserDefaults().setObject(myText3, forKey: "key5")
NSUserDefaults.standardUserDefaults().setObject(myText4, forKey: "key6")
NSUserDefaults.standardUserDefaults().synchronize()
var alert = UIAlertController(title: "Guardado", message:"Tu texto se ha guardado", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
//Hide keyboard with return button
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
if text == "\n"
{
primerTextView.resignFirstResponder()
segundoTextView.resignFirstResponder()
tercerTextView.resignFirstResponder()
cuartoTextView.resignFirstResponder()
quintoTextView.resignFirstResponder()
sextoTextView.resignFirstResponder()
return false
}
return true
}
//Hide keyboard with touching anywhere
func DismissKeyboard(){
view.endEditing(true)
}
}

I guess that in this part:
NSUserDefaults.standardUserDefaults().setObject(myText, forKey: "key2")
NSUserDefaults.standardUserDefaults().setObject(myText2, forKey: "key")
NSUserDefaults.standardUserDefaults().setObject(myText3, forKey: "key3")
NSUserDefaults.standardUserDefaults().setObject(myText4, forKey: "key4")
NSUserDefaults.standardUserDefaults().setObject(myText3, forKey: "key5")
NSUserDefaults.standardUserDefaults().setObject(myText4, forKey: "key6")
It should be:
NSUserDefaults.standardUserDefaults().setObject(myText2, forKey: "key2")
NSUserDefaults.standardUserDefaults().setObject(myText, forKey: "key")
NSUserDefaults.standardUserDefaults().setObject(myText3, forKey: "key3")
NSUserDefaults.standardUserDefaults().setObject(myText4, forKey: "key4")
NSUserDefaults.standardUserDefaults().setObject(myText5, forKey: "key5")
NSUserDefaults.standardUserDefaults().setObject(myText6, forKey: "key6")
It looks like a copy/paste error: put myText5 and myText6 instead of myText3 and myText4 in the two last lines.

Related

How do I give screenshot file a filename when sharing via UIActivityView

I have created a VC with a print and share friendly version of a bunch of calculations. When I press "share" there appears the little icon and all the share options which is great. I cannot figure out how to add a filename of some kind beside the little icon. I think this would look much more professional if I could get this accomplished.
Hope there is a simple solution someone could help with :)
Here is my code:
import UIKit
class EvenPrintableViewController: UIViewController {
#IBOutlet weak var widthSizeTransfer: UILabel!
#IBOutlet weak var heightSizeTransfer: UILabel!
#IBOutlet weak var lengthTransfer: UILabel!
#IBOutlet weak var calcOutput: UILabel!
// Instantiate variables for Even transfer
var largeSizeRelay: String?
var lengthSizeRelay: String?
var heightRelay: String?
var calcOutputRelay: String?
override func viewDidLoad() {
super.viewDidLoad()
// Sets share icon to share/print view
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareTapped))
// Assign labels to Metric Even VC values via instances above
widthSizeTransfer.text = witdhSizeRelay
heightSizeTransfer.text = heightSizeRelay
heightTransfer.text = heightRelay
calcOutput.text = calcOutputRelay
}
// Share function for share button
#objc func shareTapped() {
let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { ctx in
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}
let vc = UIActivityViewController(activityItems: [image], applicationActivities: [])
vc.excludedActivityTypes = [.assignToContact, .addToReadingList]
vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
present(vc, animated: true)
}
}
First save the UIImage as a temporary png/jpg file:
guard let imageData = image.pngData() else { return }
Then save it as a temporary file, which lets you to choose a file name:
let tempDir = FileManager.default.temporaryDirectory
let imgFileName = "YOUR_IMG_FILE_NAME.png"
let tempImgDir = tempDir.appendingPathComponent(imgFileName)
try? imageData.write(to: tempImgDir)
Then you can share the URL instead:
// Your code
let vc = UIActivityViewController(activityItems: [tempImgDir], applicationActivities: [])
P.S. the file is only temporary.

Swift XIB set label text

I am attempting to create an 'alert banner' which displays a pin in a label within the alert banner.
I am calling the alert banner from 'ViewController.swift' with:
AlertBanner().Show(self, pin: 2520)
Fatal error: Unexpectedly found nil while implicitly unwrapping an
Optional value
The error is telling me that the AlertBannerText label is nil. I suspect it has not been created yet, but how would I go about waiting for the label to exist before populating it?
Any the code in the AlertBanner class:
class AlertBanner : UIView {
#IBOutlet var AlertBannerText: UILabel!
static weak var delegate: AlertBannerDelegate!
func Show(_ vc: ViewController, pin: Int){
var onlineBanner: UIView?
var topPadding: CGFloat?
var menuView: UIView?
AlertBannerText.text = "\(pin)"
let window = UIApplication.shared.keyWindow!
if let menu = vc.view.viewWithTag(3) { menuView = menu}
onlineBanner = UINib(nibName: "AlertBanner", bundle: nil).instantiate(withOwner: nil, options: nil).first as? AlertBanner
if #available(iOS 11.0, *) { topPadding = window.safeAreaInsets.top }
onlineBanner?.frame.origin.y = 0 - (window.frame.size.width / 7.5 + topPadding!)
onlineBanner!.frame.size.width = window.frame.size.width
onlineBanner!.frame.size.height = window.frame.size.width / 5
onlineBanner!.tag = 2
vc.view.insertSubview(onlineBanner!, belowSubview: menuView!)
if let banner = vc.view.viewWithTag(2) {
UIView.animate(withDuration: 0.5, delay: 0.0, options: [], animations: {
banner.frame.origin.y = window.frame.size.width / 7.5 + topPadding!
}, completion: nil)
}
}
Doing this
AlertBanner().//////
creates an instance without the layout , hence all outlets are nil , you need to create an instance with
class func getInstance() -> AlertBanner {
let onlineBanner = UINib(nibName: "AlertBanner", bundle: nil).instantiate(withOwner: nil, options: nil).first as! AlertBanner
return onlineBanner
}
and then
AlertBanner.getInstance().//////

How to Ask for Initials for Game in Swift

I am making a game in Swift that records the high score and initials (similar to pinball records) and displays it on the game screen as labels. I am using the code below to record the high score and initials on my phone and update them. For the time being, this program will only be on my phone so I am not concerned about storing or updating data on a remote database.
What I don't know how to do (yet) is make a little popup asking the user to enter their initials on a keyboard when the quit button is pressed, if they have the current high score. Ideally, I want it to be able to only accept 3 characters and to update the initials label immediately, before the user is taken to a different view controller.
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var highScoreLabel: UILabel!
#IBOutlet weak var highScoreInitialsLabel: UILabel!
var score : Int = 0
//Stores and sets high score initials
var oldHighScoreInitials : String = "AAA"
var highScoreInitials : String {
get {
return UserDefaults.standard.string(forKey: "highScoreInitials") ?? "AAA"
}
set {
UserDefaults.standard.set(newValue, forKey: "highScoreInitials")
}
}
//Stores and sets high score
var oldHighScore : Int = 0
var highScore : Int {
get {
return UserDefaults.standard.integer(forKey: "highScore")
}
set {
UserDefaults.standard.set(newValue, forKey: "highScore")
}
}
override func viewDidLoad() {
super.viewDidLoad()
//Updates high score and initials labels with stored highest score and associated initials
highScoreLabel.text = String(highScore)
highScoreInitialsLabel.text = String(highScoreInitials)
oldHighScore = highScore
oldHighScoreInitials = highScoreInitials
}
//Asks for initials if new high score, and segues to Main VC
#IBAction func quitButtonPressed(_ sender: AnyObject) {
if (score > highScore){
highScore = score
print("Ask for initials")
print("Game over, thanks for playing!"
print("Segue to Main VC")
}
else {
print("Game over, thanks for playing!")
print("Segue to Main VC")
}
}
Thank you very much to anybody that offers assistance or advice.
Here you go, pretty simple using UIAlertViewController:
//Asks for initials if new high score, and segues to Main VC
#IBAction func quitButtonPressed(_ sender: AnyObject) {
if (score > highScore){
highScore = score
let alert = UIAlertController(title: "NEW HIGH SCORE", message: "Please enter your initials", preferredStyle: .alert)
alert.addTextField(configurationHandler: configurationTextField)
alert.addAction(UIAlertAction(title: "DONE", style: .default, handler:{ (action) in
//First example of updating initials
guard alert.textFields![0].text?.characters.count != 0 else{
return
}
self.oldHighScore = self.highScore
self.oldHighScoreInitials = alert.textFields![0].text
//Segue to Main VC
}))
present(alert, animated: true, completion: nil)
}
else {
print("Game over, thanks for playing!")
print("Segue to Main VC")
}
}
func configurationTextField(textField: UITextField!){
textField.delegate = self
textField.textAlignment = .center
textField.placeholder = "_ _ _"
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let count = text.count + string.count - range.length
return count <= 3
}
//Second example of updating initials
func textFieldDidEndEditing(_ textField: UITextField) {
oldHighScore = highScore
oldHighScoreInitials = textField.text
}
And finally your controller should conform to the UITextFieldDelegate protocol:
class yourController: UIViewController, UITextFieldDelegate
After working with Arie Pinto, we determined that my segue was preventing the alert from working and was presenting an error stating that my program was attempting to present an alert whose view was not in the window hierarchy.
I programmed my segue by ctrl+dragging my quit button to a different view controller, without writing any code.
My solution to this will be to write in performSegue code in the quitButtonPressed function to allow the alert and initial update code to perform their actions before changing windows.

How can I make this animation work?

I was trying to animate a set of images using this tutorial: https://www.geekylemon.com/animated-loading-screen. I converted the code from objective c to swift in order to implement it into another project, but it seems like it doesn't work properly.
Well, on the the storyboard are three Image Views(AnitmationimageView beeing the same with "L1.png", Loadimageview and the background image of the view controller). I wanted to run the AnitmationimageView and after it a transition to L1,2,3,4 images and after them to Loadimageview and after it to the background image. But when I run the program it only shows me the transition from AnitmationimageView to Loadimageview and the transition from Loadimageview to the background image. Hope this helps in "diagnosing" my problem.
class ViewController: UIViewController {
#IBOutlet weak var AnitmationimageView: UIImageView!
#IBOutlet weak var Loadimageview: UIImageView!
var loading_1: UIImage!
var loading_2: UIImage!
var loading_3: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
AnitmationimageView.animationImages = [UIImage(named: "L1.png"), UIImage(named: "L2.png"), UIImage(named: "L3.png"), UIImage(named: "L4.png")] as? [UIImage]
AnitmationimageView.animationRepeatCount = 1
AnitmationimageView.animationDuration = 3 as CFTimeInterval
AnitmationimageView.startAnimating()
perform(#selector(self.delay1), with: nil, afterDelay: 3)
delay1()
delay2()
delay3()
}
#objc func delay1() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.0)
AnitmationimageView.alpha = 0
UIView.commitAnimations()
perform(#selector(self.delay2), with: nil, afterDelay: 1.0)
}
#objc func delay2() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.0)
Loadimageview.alpha = 1
UIView.commitAnimations()
perform(#selector(self.delay3), with: nil, afterDelay: 1.5)
}
#objc func delay3() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.0)
Loadimageview.alpha = 0
UIView.commitAnimations()
}
}

NSUserDefault issue

I am creating a divelog app. When someone select a new dive, they will get an alert with two options: "Blank template" or "Use last dive as template".
The issue is with the later, last dive as a template.
Each dive I record the data to the NSUserDefaults. So, when someone wants last dive as a template, I just call each of the defaults and populate the tableview.
However, I am getting a nil error on the first field, the diveSiteTextfield.text, this baffles me:
Here is where the data gets saved to NSUserDefaults
As you can see, I added a print command to test to see if the diveSite field is nil, but it displays the correct data. The diveSiteTextfield.text is not nil.
import UIKit
import Parse
var diveUUID = NSUUID().UUIDString
class DiveDetails1VC: UIViewController, UITextFieldDelegate, UITableViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource
{
let userDefault = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var ratingControl: DiveSiteRating!
#IBOutlet weak var diveSiteTextfield: UITextField!
#IBOutlet weak var diveDurationTextfield: UITextField!
...
func toDive2NewParse () {
let diveObject = PFObject(className: "divelog")
diveObject["diveNumber"] = diveNumberInt
diveObject["diveSite"] = diveSiteTextfield.text
diveObject["diveDuration"] = diveDurationTextfield.text
diveObject["maxDepth"] = diveMaxDepthTextfield.text
diveObject["diveDate"] = diveDateTextfield.text
diveObject["diveTime"] = diveTimeTextfield.text
diveObject["bodyOfWater"] = diveBodyOfWaterTextfield.text
diveObject["diveBuddy"] = diveBuddyTextfield.text
diveObject["diveCity"] = diveCityTextfield.text
diveObject["maxDepthSymbol"] = diveMaxDepthSymbolTextField.text
diveObject["diveCountry"] = diveCountryTextField.text
diveObject["uuid"] = "\(diveUUID)"
// diveObject["diveRating"] = ratingControl
diveObject["entryFrom"] = "Divelog"
if PFUser.currentUser()!.username == nil {
diveObject["username"] = "Not Signed in"
} else {
diveObject["username"] = PFUser.currentUser()!.username
}
diveObject.saveEventually()
userDefault.setObject(diveNumberInt, forKey: "diveNumber")
userDefault.setObject(diveSiteTextfield.text, forKey: "diveSite")
userDefault.setObject(diveDurationTextfield.text!, forKey: "diveDuration")
userDefault.setObject(diveMaxDepthTextfield.text, forKey: "diveDepth")
userDefault.setObject(diveMaxDepthSymbolTextField.text, forKey: "symbol_maxDepth")
userDefault.setObject(diveDateTextfield.text, forKey: "entryDate")
userDefault.setObject(diveTimeTextfield.text, forKey: "entryTime")
userDefault.setObject(diveCityTextfield.text, forKey: "diveCity")
userDefault.setObject(diveCountryTextField.text, forKey: "diveCountry")
userDefault.setObject(diveBodyOfWaterTextfield.text, forKey: "bodyOfWater")
userDefault.setObject(diveBuddyTextfield.text, forKey: "diveBuddy")
userDefault.setObject(diveUUID, forKey: "uuid")
userDefault.synchronize()
print("DiveSite is ...\(userDefault.objectForKey("diveSite"))")
}
Here is the UIAlertAction that retrieves the "last dive":
#IBAction func addNewDive (sender: AnyObject) {
let alertController = UIAlertController(title: "New Dive", message: "Choose a template", preferredStyle:UIAlertControllerStyle.ActionSheet)
let buttonOne = UIAlertAction(title: "Blank template", style: .Default, handler: { (action) -> Void in
self.performSegueWithIdentifier("segueNewDive1", sender: self)
print("Button One Pressed")
})
let buttonTwo = UIAlertAction(title: "Use last dive as template", style: .Default, handler: { (action) -> Void in
self.VC1.diveSiteTextfield.text = self.userDefault.stringForKey("diveSite")
self.VC1.diveDurationTextfield.text = self.userDefault.stringForKey("diveDuration")
self.VC1.diveMaxDepthTextfield.text = self.userDefault.stringForKey("diveDepth")
...
self.DNo.textView.text = self.userDefault.objectForKey("diveNotes") as? String;
self.userDefault.synchronize()
self.performSegueWithIdentifier("segueNewDive1", sender: self)
any help on understanding why the nil will be greatly appreciated.
Updated with Vladian's comment