Unexpectedly found nil while unwrapping an Optional value / Swift - ios

Building the ToDo app. The app crashes when the new todo task is created.
The breakpoint stops the code and returns:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
#IBAction func doneButton(_ sender: UIButton) {
guard let title = textView.text, !title.isEmpty else {
return
}
let todo = Todo(context: managedContext)
todo.title = title
todo.priority = Int16(segmentedControl.selectedSegmentIndex)
todo.date = Date()
do {
try managedContext.save()
dismiss(animated: true)
textView.resignFirstResponder()
} catch {
print("Error saving todo: \(error)")
}
}
#IBAction func cancelButton(_ sender: UIButton) {
dismiss(animated: true)
textView.resignFirstResponder()
}
Any ideas what could have caused the app crash? Thanks

UISegmentedControlSegment is the public enum and UISegmentedControl is the UIControl
As per your comment, it seems that you have mistaken UISegmentedControl for UISegmentedControlSegment, so connect UISegmentedControl like below:
#IBOutlet weak var segmentedControl: UISegmentedControl!

Related

Swift - Accessing implicitly unwrapped variable gives a nil error

I'm following a tutorial on CoreData and I've been following it exactly, yet when they run the app, everything works and saves correctly, yet I get a nil error. The tutorial is a few years old, so I'm not sure if something has been udpated in the way CoreData works. It's an app to save goals.
Here's the first view controller where you enter the text of the goal and if it is short or long term:
import UIKit
class CreateGoalViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var goalTextView: UITextView!
#IBOutlet weak var shortTermButton: UIButton!
#IBOutlet weak var longTermButton: UIButton!
#IBOutlet weak var nextButton: UIButton!
var userGoalType: GoalType = .shortTerm
override func viewDidLoad() {
super.viewDidLoad()
nextButton.bindToKeyboard()
shortTermButton.setSelectedColor()
longTermButton.setDeselectedColor()
print("\(userGoalType)")
goalTextView.delegate = self
}
#IBAction func nextButtonPressed(_ sender: Any) {
if goalTextView.text != "" && goalTextView.text != "What is your goal?" {
guard let finishVC = storyboard?.instantiateViewController(withIdentifier: "FinishVC") as? FinishGoalViewController else {return}
finishVC.initData(description: goalTextView.text!, type: userGoalType)
print("\(finishVC.goalType.rawValue) after next button pressed")
performSegue(withIdentifier: "goToFinish", sender: self)
}
}
#IBAction func longTermButtonPressed(_ sender: Any) {
userGoalType = .longTerm
longTermButton.setSelectedColor()
shortTermButton.setDeselectedColor()
print("\(userGoalType)")
}
#IBAction func shortTermButtonPressed(_ sender: Any) {
userGoalType = .shortTerm
shortTermButton.setSelectedColor()
longTermButton.setDeselectedColor()
print("\(userGoalType)")
}
#IBAction func backButtonPressed(_ sender: Any) {
dismiss(animated: true)
}
func textViewDidBeginEditing(_ textView: UITextView) {
goalTextView.text = ""
goalTextView.textColor = UIColor(ciColor: .black)
}
}
And here's the following view controller where you set the number of times you want to do that goal where the CoreData functions are:
import UIKit
import CoreData
class FinishGoalViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var createButton: UIButton!
#IBOutlet weak var pointsTextField: UITextField!
var goalDescription: String!
var goalType: GoalType!
func initData(description: String, type: GoalType) {
self.goalDescription = description
self.goalType = type
}
override func viewDidLoad() {
super.viewDidLoad()
createButton.bindToKeyboard()
pointsTextField.delegate = self
}
#IBAction func createGoalPressed(_ sender: Any) {
if pointsTextField.text != ""{
self.save { finished in
if finished {
dismiss(animated: true)
}
}
}
}
#IBAction func backButtonPressed(_ sender: Any) {
dismiss(animated: true)
}
func save(completion: (_ finished: Bool) -> ()) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else {return}
let goal = Goal(context: managedContext)
goal.goalDescription = goalDescription
goal.goalType = goalType.rawValue
goal.goalCompletionValue = Int32(pointsTextField.text!)!
goal.goalProgress = Int32(0)
do{
try managedContext.save()
print("successfully saved data")
completion(true)
}catch{
debugPrint("Could not save: \(error.localizedDescription)")
completion(false)
}
}
}
I'm getting a nil error in the save function with the goalType.rawValue turning up nil. The goal type is set up in an enum file:
import Foundation
enum GoalType: String {
case longTerm = "Long Term"
case shortTerm = "Short Term"
}
I'm not sure why there's an error. Because in the CreateGoalViewController, I print the goalType.rawValue from the following view controller and it comes up with the correct string, either short or long-term. But when FinishGoalViewController loads, it is all of a sudden nil.
You are initiating and configuring your FinishGoalViewController in nextButtonPressed but you never use it. performSegue(withIdentifier: "goToFinish", sender: self) will create and push a new instance of FinishGoalViewController.
The most simple aproach would be to push your allready configured controller from your curent Controller. Remove performSegue(... and use.
self.navigationController?.pushViewController(finishVC, animated: true)
If you still want to use the segue, remove everything from the nextButtonPressed function, leaving just the performSegue(... line. After that add this function to your CreateGoalViewController controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToFinish" {
if let finishVC = segue.destination as? FinishGoalViewController {
// configure finshVC here
}
}
}

Getting API data + Optional Problems

I'm struggling to get an optional type to a Label.text. It keeps on giving me "nil" value and won't change the text.
import UIKit
class VerifyPNViewController: UIViewController {
#IBOutlet weak var VerificationMessage: UILabel!
#IBAction func backButton(_ sender: Any) {
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
func didSuccess(_ response: GetLoginVerificationMessage){
let Main = response.result!
DispatchQueue.main.async {
print(Main)
self.VerificationMessage?.text = Main
print(self.VerificationMessage?.text)
}
}
}
and I will get a
234443 << which is a response.result!
nil << print(self.VerificationMessage?.text)
I have no idea why this value won't go into the "self. Verification?.text" Does anyone have ideas?
Thank you.

iOS How do I add a new item to a collection view

So I have a CollectionView as my home view, then I have a second view as a table view controller that adds a single image to itself. As soon as I press the “save” button on the top right I get the error code: See image of what I'm trying to acheive
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
I have a model of array items that take in only images. How can I pass my uploaded image to my CollectionView from my Table View and update the CollectionView with the uploaded item
This is where the error occurs:
#IBAction func saveButtonPressed(_ sender: UIBarButtonItem) {
if let uploadedImage = uploadImageView.image {
items.image = uploadedImage
}
dismiss(animated: true, completion: nil)
}
You get this issue when you're force unwrapping an optional and it's actually empty. Try:
#IBAction func saveButtonPressed(_ sender: UIBarButtonItem) {
if let uploadedImage = uploadImageView?.image {
items.image = uploadedImage
} else {
print("uploadImageView is nil check the #IBOutlet connection for uploadImageView!!!")
}
dismiss(animated: true, completion: nil)
}
for this problem i suggest you to use guard to made sure your optional variable is not nil
#IBAction func saveButtonPressed(_ sender: UIBarButtonItem) {
guard let uploadedImage = uploadImageView.image else {
//do something if nill here
return
}
items.image = uploadedImage
dismiss(animated: true, completion: nil)
}

Duplicate values after saving to CoreData

I currently have 2 views in my project: a ViewController with a TableView that shows a list of Transactions and a ViewController for creating a new Transaction.
The issue that I am having is that after creating a new Transaction, it successfully loads onto my TableView, but when I force close and reopen the app, the value is duplicated. As far as I can tell and know, the save() function is only being called once and nothing of the sort is going on in AppDelegate/SceneDelegate. See GIF for an example of what's going on.
GIF Demonstrating Issue
This is my TranasctionsTableViewController:
class TransactionsTableViewController: UIViewController {
// MARK: - Properties
var entries: [NSManagedObject] = []
var container: NSPersistentContainer!
// MARK: - IBOutlets
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// setup persistent container
container = NSPersistentContainer(name: "expenses")
// load store
container.loadPersistentStores { storeDescription, error in
if let error = error {
print("Unresolved error \(error)")
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier! {
case "NewTransactionSegue":
// pass an entry to the destination segue
let destination = segue.destination as! UINavigationController
let targetController = destination.topViewController as! NewTransactionViewController
let managedContext = container.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Entry", in: managedContext)!
let entry = NSManagedObject(entity: entity, insertInto: managedContext)
targetController.entry = entry as? Entry
default:
print("Unknown segue: \(segue.identifier!)")
}
}
#IBAction func unwindToTransactionList(sender: UIStoryboardSegue) {
print("unwind segue called!")
if let sourceViewController = sender.source as? NewTransactionViewController, let entry = sourceViewController.entry {
print(entry)
self.save(entryDescription: entry.entryDescription, amount: entry.amount, date: entry.date, id: entry.id)
// reset the tableView to defaults if no data message was displayed before loading data.
if self.tableView.backgroundView != nil {
self.tableView.backgroundView = nil
self.tableView.separatorStyle = .singleLine
}
self.tableView.reloadData()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// load managedCOntext
let managedContext = container.viewContext
// try to fetch data from CoreData. If successful, load into entries.
do {
entries = try managedContext.fetch(Entry.fetchRequest())
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
// save a new entry to the data store
func save(entryDescription: String, amount: Double, date: Date, id: UUID) {
print("save called!!")
let managedContext = container.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Entry", in: managedContext)!
let entry = NSManagedObject(entity: entity, insertInto: managedContext)
entry.setValue(entryDescription, forKey: "entryDescription")
entry.setValue(amount, forKey: "amount")
entry.setValue(date, forKey: "date")
entry.setValue(id, forKey: "id")
do {
try managedContext.save()
entries.append(entry)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
// save the current container context
func saveContext() {
if container.viewContext.hasChanges {
do {
try container.viewContext.save()
} catch {
print("An error occurred while saving: \(error)")
}
}
}
}
This is my NewTransactionViewController:
class NewTransactionViewController: UIViewController, UITextFieldDelegate {
/*
This value is either passed by `TransactionTableViewController` in `prepare(for:sender:)`
or constructed as part of adding a new transaction.
*/
var entry: Entry?
// MARK: - IBOutlets
#IBOutlet weak var transactionDescriptionLabel: UILabel!
#IBOutlet var transactionDescriptionTextField: UITextField!
#IBOutlet var transactionAmountLabel: UILabel!
#IBOutlet var transactionAmountTextField: UITextField!
#IBOutlet weak var cancelButton: UIBarButtonItem!
#IBOutlet weak var saveButton: UIBarButtonItem!
// MARK: Constants
let TRANSACTION_DESCRIPTION_TEXT_FIELD_TAG = 0
let TRANSACTION_AMOUNT_TEXT_FIELD_TAG = 1
override func viewDidLoad() {
super.viewDidLoad()
// Handle textfield input through delegate callbacks.
transactionDescriptionTextField.delegate = self
transactionAmountTextField.delegate = self
// Adds done button to keypad
transactionAmountTextField.addDoneButtonToKeyboard(myAction: #selector(self.transactionAmountTextField.resignFirstResponder))
}
// MARK: - UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// If the First Responder is the Description Text Field, transfer First Responder to Amount Text Field
if (textField.tag == TRANSACTION_DESCRIPTION_TEXT_FIELD_TAG) {
transactionAmountTextField.becomeFirstResponder()
}
textField.resignFirstResponder()
return true
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: segue)
// Configure the destination view controller only when the save button is pressed.
guard let button = sender as? UIBarButtonItem, button === saveButton else {
os_log("The save button was not pressed, cancelling", log: OSLog.default, type: .debug)
return
}
let transactionDescription = transactionDescriptionTextField.text ?? ""
let transactionAmount = Double(transactionAmountTextField.text!) ?? 0.00
// Set the entry to be passed to TransactionTableViewController after the unwind segue.
entry?.setValue(transactionDescription, forKey: "entryDescription")
entry?.setValue(transactionAmount, forKey: "amount")
entry?.setValue(UUID(), forKey: "id")
entry?.setValue(Date(), forKey: "date")
}
// MARK: - IBActions
#IBAction func cancelButtonTapped(sender: UIBarButtonItem) {
}
#IBAction func saveButtonTapped(sender: UIBarButtonItem) {
}
}

UITextField nil on button click, but works onchange

I'm getting the following error on button click
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
following is the code
#IBOutlet weak var UserId: UITextField!{
didSet{
UserId.setBottomBorder()
UserId.delegate = self
}
}
#IBOutlet weak var Password: UITextField!{
didSet{
Password.setBottomBorder()
Password.delegate = self
}
}
#IBAction func logincta(_ sender: Any) {
guard let _ = UserId.text, UserId.text?.characters.count != 0 else {
print("test")
return
}
}
but works fine in the following onchange code
#IBAction func UserIdChanged(_ sender: Any) {
if UserId.text == "" {
UserId.setBottomBorder()
}
else{
UserId.setPurpleBottomBorder()
}
}
#IBAction func PasswordChanged(_ sender: Any) {
if Password.text == "" {
Password.setBottomBorder()
}
else{
Password.setPurpleBottomBorder()
}
}
i wonder how it worked in onchange event "if UserId.text == "" but not in button click
I've tried your code and it seems to work...
Anyway maybe try to use the guard in this way:
guard let numOfChars = UserId?.text?.count, numOfChars != 0 else {
print("test")
return
}

Resources