Je continue à avoir cette erreur: Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<FoodTracker.MealViewController 0x7faa9ed189d0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key cancel.'
J'essaie de compléter le Apple destiné aux développeurs pour se familiariser avec les applications iOS. Mon code et mon storyboard ressemblent exactement à ceux du fichier exemple. J'espère qu'un œil neuf capable de voir quelque chose que je ne suis pas?
import UIKit
import os.log
class MealViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//MARK: Properties
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var photoImageView: UIImageView!
@IBOutlet weak var ratingControl: RatingControl!
@IBOutlet weak var saveButton: UIBarButtonItem!
/*
This value is either passed by 'MealTableViewController' in
'prepare(for:sender) or constructed as part of adding a new meal.
*/
var meal: Meal?
override func viewDidLoad() {
super.viewDidLoad()
// Handle the text field's user input through delegate callbacks
nameTextField.delegate = self
// Enable save button only if text field has valid Meal name
updateSaveButtonState()
}
//MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Hide the keyboard
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
updateSaveButtonState()
navigationItem.title = textField.text
}
func textFieldDidBeginEditing(_ textField: UITextField) {
// Disable save button while editing
saveButton.isEnabled = false
}
//MARK: UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// Dismiss the picker if the user canceled
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image
photoImageView.image = selectedImage
// Dismiss the picker
dismiss(animated: true, completion: nil)
}
//MARK: Navigation
@IBAction func cancel(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
// Configure view controller before it's presented
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
// Configure destination view controller only when save button 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 name = nameTextField.text ?? ""
let photo = photoImageView.image
let rating = ratingControl.rating
// Set meal to be passed to MealTableViewController after unwind segue
meal = Meal(name: name, photo: photo, rating: rating)
}
//MARK: Actions
@IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
// Hide the keyboard
nameTextField.resignFirstResponder()
// UIImagePickerController is a view controller that lets a user pick media from their photo library
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked, not taken
imagePickerController.sourceType = .photoLibrary
// Make sure ViewController is notified when the user picks an image
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
//MARK: Private Methods
private func updateSaveButtonState() {
// Disable the save button if the text field is empty
let text = nameTextField.text ?? ""
saveButton.isEnabled = !text.isEmpty
}
}
Il existe quelques autres fichiers, mais faites-le moi savoir ce dont vous avez besoin, car je suis très novice dans Swift/XCode et je ne sais pas trop quoi fournir/ne pas fournir.
Cela signifie que vous avez quelque chose sur votre storyboard connecté à IBOutlet appelé cancel
mais que vous n'avez pas cet IBOutlet dans votre classe. Le compilateur ne trouve donc pas la clé cancel
(propriété) dans votre classe. Vous devriez trouver ce bouton (je pense que c'est un UIButton à cause de son nom) dans le storyboard, cliquez dessus avec le bouton droit de la souris et cliquez sur "x" pour supprimer cette connexion. Ou vous voudrez peut-être supprimer ce bouton. Ou vous voudrez peut-être ajouter cet IBOutlet à votre classe.
Je suis d’accord avec ce que Alex Shubin a mentionné dans sa réponse, une solution utilisable telle que "recherchez toutes les connexions qui n'existent plus et supprimez-les". J'avais le même problème et sa suggestion a corrigé ce bogue. Pour ceux qui débutent en programmation et Xcode comme moi, un peu plus d’informations sur la façon de localiser le bouton x dans le scénarimage pourraient être utiles.
Cliquez sur le cercle jaune en haut du contrôleur de vue dans le storyboard.
Ensuite, affichez l'inspecteur de connexions dans le coin supérieur droit de la barre des utilitaires. L'inspecteur de connexions est le menu à l'extrême droite, un cercle avec une flèche pointant vers la droite. Cliquez dessus et vous devriez voir toutes les connexions pour ce contrôleur de vue.
J'inclus une capture d'écran de ce à quoi cela ressemble dans mon application.
Recherchez le nom du module sous "Identity Inspector". Le nom du module doit être sélectionné ou "Hériter le module de la cible" doit être vérifié. S'il y a plusieurs modules, sélectionnez celui qui convient.