首页 > 解决方案 > Swift 文本框问题

问题描述

此应用程序旨在让他们的用户对约克学院的宿舍进行评分。为了学习语言,我使用了苹果开发者网站并按照他们的分步说明制作了基本应用程序。添加一些小功能后,我尝试添加一个文本框,供用户添加每个宿舍的描述。它运行,但似乎没有显示已添加到描述部分的文本。这是用旧版本的 Swift 编写的。

https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/index.html#//apple_ref/doc/uid/TP40015214-CH2-SW1

     **MealTableViewController.swift**
    //  MealTableViewController.swift
    //  FoodTracker
    //
    //  Created by Jane Appleseed on 11/15/16.
    //  Copyright © 2016 Apple Inc. All rights reserved.
    //

    import UIKit
    import os.log

    class MealTableViewController: UITableViewController {

        //MARK: Properties

        var meals = [Meal]()

        override func viewDidLoad() {
            super.viewDidLoad()

            // Use the edit button item provided by the table view controller.
            navigationItem.leftBarButtonItem = editButtonItem

            // Load any saved meals, otherwise load sample data.
            if let savedMeals = loadMeals() {
                meals += savedMeals
            }
            else {
                // Load the sample data.
                loadSampleMeals()
            }
        }

        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }

        //MARK: - Table view data source

        override func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }

        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return meals.count
        }


        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            // Table view cells are reused and should be dequeued using a cell identifier.
            let cellIdentifier = "MealTableViewCell"

            guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? MealTableViewCell  else {
                fatalError("The dequeued cell is not an instance of MealTableViewCell.")
            }

            // Fetches the appropriate meal for the data source layout.
            let meal = meals[indexPath.row]

            cell.nameLabel.text = meal.name
            cell.photoImageView.image = meal.photo
            cell.ratingControl.rating = meal.rating
            cell.descriptionLabel?.text = meal.desc

            print(meal.desc!)

            return cell
        }



        // Override to support conditional editing of the table view.
        override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
            // Return false if you do not want the specified item to be editable.
            return true
        }



        // Override to support editing the table view.
        override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
            if editingStyle == .delete {
                // Delete the row from the data source
                meals.remove(at: indexPath.row)
                saveMeals()
                tableView.deleteRows(at: [indexPath], with: .fade)
            } else if editingStyle == .insert {
                // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
            }    
        }


        /*
        // Override to support rearranging the table view.
        override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {

        }
        */

        /*
        // Override to support conditional rearranging of the table view.
        override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
            // Return false if you do not want the item to be re-orderable.
            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: sender)

            switch(segue.identifier ?? "") {

            case "AddItem":
                os_log("Adding a new meal.", log: OSLog.default, type: .debug)

            case "ShowDetail":
                guard let mealDetailViewController = segue.destination as? MealViewController else {
                    fatalError("Unexpected destination: \(segue.destination)")
                }

                guard let selectedMealCell = sender as? MealTableViewCell else {
                    fatalError("Unexpected sender: \(String(describing: sender))")
                }

                guard let indexPath = tableView.indexPath(for: selectedMealCell) else {
                    fatalError("The selected cell is not being displayed by the table")
                }

                let selectedMeal = meals[indexPath.row]
                mealDetailViewController.meal = selectedMeal

            default:
                fatalError("Unexpected Segue Identifier; \(String(describing: segue.identifier))")
            }
        }


        //MARK: Actions

        @IBAction func unwindToMealList(sender: UIStoryboardSegue) {
            if let sourceViewController = sender.source as? MealViewController, let meal = sourceViewController.meal {

                if let selectedIndexPath = tableView.indexPathForSelectedRow {
                    // Update an existing meal.
                    meals[selectedIndexPath.row] = meal
                    tableView.reloadRows(at: [selectedIndexPath], with: .none)
                }
                else {
                    // Add a new meal.
                    let newIndexPath = IndexPath(row: meals.count, section: 0)

                    meals.append(meal)
                    tableView.insertRows(at: [newIndexPath], with: .automatic)
                }

                // Save the meals.
                saveMeals()
                os_log("Saved Meals?", log: OSLog.default, type: .debug)

            }
        }

        //MARK: Private Methods
        //*** MAKE SAMPLE DORMS ***
        private func loadSampleMeals() {

            let photo1 = UIImage(named: "meal1")
            let photo2 = UIImage(named: "meal2")
            let photo3 = UIImage(named: "meal3")

            guard let meal1 = Meal(name: "Northside Commons", photo: photo1, rating: 5, desc: "Great Rooms, air conditioning") else {
                fatalError("Unable to instantiate dorm1")
            }

            guard let meal2 = Meal(name: "Beard Hall", photo: photo2, rating: 2, desc: "Lots of space") else {
                fatalError("Unable to instantiate meal2")
            }

            guard let meal3 = Meal(name: "Mannor Hall", photo: photo3, rating: 3, desc: "No air conditioning, fun floor mates") else {
                fatalError("Unable to instantiate meal2")
            }

            meals += [meal1, meal2, meal3]
        }

        private func saveMeals() {
            let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(meals, toFile: Meal.ArchiveURL.path)
            if isSuccessfulSave {
                os_log("Meals successfully saved.", log: OSLog.default, type: .debug)
            } else {
                os_log("Failed to save meals...", log: OSLog.default, type: .error)
            }
        }

        private func loadMeals() -> [Meal]?  {
            return NSKeyedUnarchiver.unarchiveObject(withFile: Meal.ArchiveURL.path) as? [Meal]
        }

    }



//
//  Meal.swift
//  FoodTracker
//
//  Created by Jane Appleseed on 11/10/16.
//  Copyright © 2016 Apple Inc. All rights reserved.
//

import UIKit
import os.log


class Meal: NSObject, NSCoding {

    //MARK: Properties

    var name: String
    var photo: UIImage?
    var rating: Int
    var desc: String?

    //MARK: Archiving Paths
    static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
    static let ArchiveURL = DocumentsDirectory.appendingPathComponent("meals")

    //MARK: Types

    struct PropertyKey {
        static let name = "name"
        static let photo = "photo"
        static let rating = "rating"
        static let desc = "desc"
    }

    //MARK: Initialization

    init?(name: String, photo: UIImage?, rating: Int, desc: String?) {

        // The name must not be empty
        guard !name.isEmpty else {
            return nil
        }
        /*
        guard !desc?.isEmpty else {
            return nil
        }
*/
        // The rating must be between 0 and 5 inclusively
        guard (rating >= 0) && (rating <= 5) else {
            return nil
        }

        // The rates must be above 0
        guard (rating >= 0) else {
            return nil
        }

        // Initialization should fail if there is no name or if the rating is negative.
        if name.isEmpty || rating < 0  {
            return nil
        }

        // Initialize stored properties.
        self.name = name
        self.photo = photo
        self.rating = rating
        self.desc = desc

    }

    //MARK: NSCoding

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: PropertyKey.name)
        aCoder.encode(photo, forKey: PropertyKey.photo)
        aCoder.encode(rating, forKey: PropertyKey.rating)
        aCoder.encode(desc, forKey: PropertyKey.desc)
    }

    required convenience init?(coder aDecoder: NSCoder) {

        // The name is required. If we cannot decode a name string, the initializer should fail.
        guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
            os_log("Unable to decode the name for a Meal object.", log: OSLog.default, type: .debug)
            return nil
        }
        /*
        guard (aDecoder.decodeObject(forKey: PropertyKey.desc) as? String) != nil else {
                   os_log("Unable to decode the description for a Meal object.", log: OSLog.default, type: .debug)
                   return nil
               }
        */
        // Because photo is an optional property of Meal, just use conditional cast.
        let photo = aDecoder.decodeObject(forKey: PropertyKey.photo) as? UIImage

        let rating = aDecoder.decodeInteger(forKey: PropertyKey.rating)

        // Must call designated initializer.
        self.init(name: name, photo: photo, rating: rating, desc: "desc")

    }
}

标签: swift

解决方案


我知道这不是一个硬性和快速的答案(很难给出一个没有 XIB/Storyboard 文件的答案),但我看到您的描述标签 ( cell.descriptionLabel?) 是可选的。我会检查您的描述标签是否确实存在,如下所示:

if let descriptionLabel = cell.descriptionLabel? {
    descriptionLabel.text = meal.desc
} else {
    print("This label doesn't exist!")    
}

然后检查你的输出!


推荐阅读