web-dev-qa-db-fra.com

Cette classe n'est pas compatible avec le codage de valeur de clé pour l'annulation de clé

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.

17
Ethan

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.

37
Alex Shubin

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.

enter image description here

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.

enter image description here

13
llamacorn

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.

6