web-dev-qa-db-ja.com

このクラスは、キーキャンセルのキー値コーディングに準拠していません

このエラーが引き続き発生します: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.'

Apple iOSアプリの使用を開始するための開発者ガイド。私のコードとストーリーボードは、サンプルファイルのコードとストーリーボードとまったく同じように見えます。私ではない何かを見ることができますか?

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
    }
}

他にもいくつかのファイルがありますが、私はSwift/XCodeが初めてで、何を提供するかしないかわからないので、必要なものを教えてください。

17
Ethan

つまり、ストーリーボード上にcancelという名前のIBOutletに接続されているものがありますが、クラスにはこのIBOutletがありません。そのため、コンパイラはクラスでKey cancel(プロパティを意味します)を見つけることができません。ストーリーボードでそのボタン(名前のせいでUIButtonだと思う)を見つけ、マウスの右ボタンをクリックし、「x」をクリックしてその接続を削除します。または、このボタンをまったく削除することもできます。または、このIBOutletをクラスに追加することもできます。

37
Alex Shubin

「もう存在しない接続を探して削除する」などの実用的なソリューションであるアレックスシュビンの答えに同意します。私は同じ問題を抱えていて、彼の提案はそのバグを修正しました。プログラミングが初めてで、私のようなXcodeをお使いの場合は、ストーリーボードでxボタンを見つける方法についてもう少し情報が役立つかもしれません。

ストーリーボードのView Controllerの上部にある黄色の丸をクリックします。

enter image description here

次に、ユーティリティバーの右上に接続インスペクターを表示します。接続インスペクターは、右端のメニュー、右向き矢印の付いた円です。それをクリックすると、そのView Controllerのすべての接続が表示されます。

アプリにどのように見えるかのスクリーンショットを含めています。

enter image description here

13
llamacorn

「Identity Inspector」でモジュール名を確認します。モジュール名を選択するか、「ターゲットからモジュールを継承」をチェックする必要があります。複数のモジュールがある場合は、適切なモジュールを選択します。

6