ISplitViewController:DetailViewController 可以从 MasterVIewController 加载数据而不返回吗?

ISplitViewController: Can DetailViewController load data from MasterVIewController without segueing back?

业余爱好者。我使用 UISplitViewController 创建了一个 iOS Swift 应用程序。到目前为止效果很好。 我希望能够在查看 DetailViewController 视图的同时加载存储在 MasterViewController 中的数据,而无需返回到 MasterViewContoler 视图并选择那里显示的 UITableView 中的项目。呸,多啰嗦,我希望这是有道理的。这可能吗?我不确定如何进行。这些图片可能会更好地解释:

Detail View

Master View

我已经阅读了这些问题:getting the MasterViewController from the DetailViewController in a UISplitViewController app and SplitView - reload data in master tableView based on detail changed in swift 但它们并不是我想要的。

这是我的 DetailViewController 代码:

import UIKit
import SafariServices

class DetailViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!

    @IBOutlet weak var stackView: UIStackView!

    @IBOutlet weak var detailDescriptionLabel: UILabel!

    @IBOutlet weak var compareToButton: UIButton!

    @IBAction func compareToButtonTapped(_ sender: Any) {
        //do something here?
    }


    @IBOutlet weak var pathologyImageViewOne: UIImageView!

    @IBOutlet weak var pathologyImageViewTwo: UIImageView!

    @IBOutlet weak var detailUsedLabel: UILabel!

    @IBOutlet weak var detailReferenceLabel: UILabel!

    @IBOutlet weak var detailPhotoOneCaptionLabel: UILabel!

    @IBOutlet weak var detailPhotoTwoCaptionLabel: UILabel!

    var caseIDOne = 0
    var caseIDTwo = 0
    var compareToButtonString = "Hello"


    func configureView() {
        // Update the user interface for the detail item.
        if let detail = detailItem {
            if let detailDescriptionLabel = detailDescriptionLabel,
                let compareToButton = compareToButton,
                let detailUsedLabel = detailUsedLabel,
                let pathologyImageViewOne = pathologyImageViewOne,
                let pathologyImageViewTwo = pathologyImageViewTwo,
                let detailReferenceLabel = detailReferenceLabel,
                let detailPhotoOneCaptionLabel = detailPhotoOneCaptionLabel,
                let detailPhotoTwoCaptionLabel = detailPhotoTwoCaptionLabel {

                title = detail.name
                caseIDOne = detail.caseIDOne
                caseIDTwo = detail.caseIDTwo!

                detailDescriptionLabel.text = detail.description
                compareToButtonString = detail.compareTo!

                UIView.performWithoutAnimation {
                    compareToButton.setTitle("\(compareToButtonString)", for: .normal)
                }

                detailUsedLabel.text = detail.used
                detailReferenceLabel.text = detail.reference

                pathologyImageViewOne.image = UIImage(named: detail.photoOne)
                pathologyImageViewOne.layer.cornerRadius = 4
                pathologyImageViewOne.contentMode = .scaleAspectFill
                pathologyImageViewOne.clipsToBounds = true

                pathologyImageViewTwo.image = UIImage(named: detail.photoTwo!)
                pathologyImageViewTwo.layer.cornerRadius = 4
                pathologyImageViewTwo.contentMode = .scaleAspectFill
                pathologyImageViewTwo.clipsToBounds = true

                // The image in the foreground
                let frontImage = UIImage(named: "tap-icon")
                // Create the view holding the image
                let frontImageViewOne = UIImageView(image: frontImage)
                // The size and position of the front image
                frontImageViewOne.frame = CGRect(x: 0 , y: 0, width: 34, height: 42)
                // turn off AutoresingMask
                frontImageViewOne.translatesAutoresizingMaskIntoConstraints = false

                // change alpha
                frontImageViewOne.alpha = 0.8

                // Create the view holding the image again
                let frontImageViewTwo = UIImageView(image: frontImage)
                // The size and position of the front image again
                frontImageViewTwo.frame = CGRect(x: 0 , y: 0, width: 34, height: 42)
                // turn off AutoresingMask again
                frontImageViewTwo.translatesAutoresizingMaskIntoConstraints = false

                // change alpha again
                frontImageViewTwo.alpha = 0.8



                //MARK: Image One
                // Add the front image on top of the background
                pathologyImageViewOne.addSubview(frontImageViewOne)

                NSLayoutConstraint.activate([
                    //place the tap icon at the bottom right of parent
                    frontImageViewOne.bottomAnchor.constraint(equalTo: pathologyImageViewOne.bottomAnchor, constant: -10),
                    frontImageViewOne.centerXAnchor.constraint(equalTo: pathologyImageViewOne.rightAnchor, constant: -24)
                    ])


                let tapGestureRecognizerOne = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizerOne:)))
                pathologyImageViewOne.isUserInteractionEnabled = true
                pathologyImageViewOne.addGestureRecognizer(tapGestureRecognizerOne)

                //MARK: Image two
                // Add the front image on top of the background
                pathologyImageViewTwo.addSubview(frontImageViewTwo)

                NSLayoutConstraint.activate([
                    //place the tap icon at the bottom right of parent
                    frontImageViewTwo.bottomAnchor.constraint(equalTo: pathologyImageViewTwo.bottomAnchor, constant: -10),
                    frontImageViewTwo.centerXAnchor.constraint(equalTo: pathologyImageViewTwo.rightAnchor, constant: -24)
                    ])


                let tapGestureRecognizerTwo = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizerTwo:)))
                pathologyImageViewTwo.isUserInteractionEnabled = true
                pathologyImageViewTwo.addGestureRecognizer(tapGestureRecognizerTwo)

                detailPhotoOneCaptionLabel.text = detail.photoOneCaption

                detailPhotoTwoCaptionLabel.text = detail.photoTwoCaption

            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()


        configureView()

        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.layoutMargins  = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
        stackView.isLayoutMarginsRelativeArrangement = true
        scrollView.addSubview(stackView)

        stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true
        stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true


    }

    var detailItem: Descriptor? {
        didSet {
            // Update the view.
           configureView()
        }
    }


    func showWebsite(_ whichCase: Int) {
        if let url = URL(string: "https://digitalpathology.uct.ac.za/case_detail.php?case_id=\(whichCase)") {
            let config = SFSafariViewController.Configuration()
            config.entersReaderIfAvailable = true

            let vc = SFSafariViewController(url: url, configuration: config)
            present(vc, animated: true)
        }
    }



    @objc func imageTapped(tapGestureRecognizerOne: UITapGestureRecognizer)
    {

       showWebsite(caseIDOne)
       print("Image tapped")
       print("CaseOne ID = \(caseIDOne)")
    }

    @objc func imageTapped(tapGestureRecognizerTwo: UITapGestureRecognizer)
    {

        showWebsite(caseIDTwo)
        print("Image tapped")
        print("CaseTwo ID = \(caseIDTwo)")
    }


}

我编辑的(为简洁起见)MasterViewController 代码:

import UIKit

class MasterViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    @IBOutlet weak var searchFooter: SearchFooter!

    var detailViewController: DetailViewController? = nil

    var descriptors = [Descriptor]()

    var filteredDescriptors = [Descriptor]()

    let searchController = UISearchController(searchResultsController: nil)

    fileprivate var collapseDetailViewController = true

    // MARK: - view setup
    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup the Search Controller
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "Search Descriptors"
        navigationItem.searchController = searchController

        definesPresentationContext = true

        //delagate and data source commented out, connected in storyboard
        //tableView.delegate = self
        //tableView.dataSource = self

        // The data
        descriptors = [
            Descriptor(name:"Friable", description:"Easily crumbled. Said of tissue that readily tears, fragments, or bleeds when gently palpated or manipulated.", photoOne: "Friable", photoOneCaption:"Subacute bacterial edocarditis",  used:"Used in relation to – heart valve vegetations, brittle carcinomatous tissue esp. of cervix.", reference: "Ref: DMD", caseIDOne:769),           
            Descriptor(name:"Hypertrophic / Hypertrophied", description:"An enlarged, overgrown or bulky organ or part, on account of an increase in the size of its cells (compare ‘hyperplastic’).", compareTo: "Hyperplastic", photoOne: "Hypertrophic1", photoOneCaption:"The heart in hypertension", photoTwo: "Hypertrophic2", photoTwoCaption:"The heart in hypertension", used:"Used in relation to – over-exercised muscles or muscular organs such as heart, bladder, stomach.", reference: "Ref: FPMD", caseIDOne:833, caseIDTwo:833),
            Descriptor(name:"Hyperplastic", description:"An enlarged or expanded organ or part, on account of an increase in the formation and number of normal cells (compare ‘hypertrophy’). Hyperplastic expansion may be uniform or nodular.",  compareTo: "Hypertrophy", photoOne: "Hyperplastic", photoOneCaption:"Hyperplastic gastropathy in Zollinger-Ellison syndrome", used:"Used in relation to - a benign expansion of the prostate, an endo- or epithelium, lymph node, gums or endocrine glands, usually reflecting hyper-stimulation of some cause.", reference: "Ref: MKEDMNAH", caseIDOne:555),]

        if let split = splitViewController {
            let controllers = split.viewControllers
           detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
        }
        //splitViewController?.delegate = self as? UISplitViewControllerDelegate
        splitViewController?.delegate = self

    }

    override func viewWillAppear(_ animated: Bool) {

        if splitViewController!.isCollapsed {
            if let selectionIndexPath = self.tableView.indexPathForSelectedRow {
                self.tableView.deselectRow(at: selectionIndexPath, animated: animated)
            }
         }



        //lets sort the array of objects so A comes before Z
        descriptors.sort { [=11=].name.compare(.name) == .orderedAscending }
        self.tableView.reloadData()

        super.viewWillAppear(animated)
    }


    // MARK: - Segues

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {


        if segue.identifier == "showDetail" {
            if let indexPath = tableView.indexPathForSelectedRow {
                let descriptor: Descriptor
                if isFiltering() {
                    descriptor = filteredDescriptors[indexPath.row]
                } else {
                    descriptor = descriptors[indexPath.row]
                }
                let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
                controller.detailItem = descriptor

                collapseDetailViewController = false

                controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
                controller.navigationItem.leftItemsSupplementBackButton = true

                let backItem = UIBarButtonItem()
                backItem.title = "Pathology A-Z"
                navigationItem.backBarButtonItem = backItem
            }
        }
    }

    // MARK: - Table View
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if isFiltering() {
            searchFooter.setIsFilteringToShow(filteredItemCount: filteredDescriptors.count, of: descriptors.count)
            return filteredDescriptors.count
        }
        searchFooter.setNotFiltering()
        return descriptors.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        let descriptor: Descriptor
        if isFiltering() {
            descriptor = filteredDescriptors[indexPath.row]
        } else {
            descriptor = descriptors[indexPath.row]
        }
        cell.textLabel!.text = descriptor.name
        cell.detailTextLabel!.text = descriptor.description
        return cell
    }

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return false
    }

extension MasterViewController: UISplitViewControllerDelegate {

    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
        return collapseDetailViewController
    }
}

您应该为默认情况准备一个方法。比如说,在 DetailViewController 中声明 detailDefaultItem 并在 configureView() 之前分配给 viewDidLoad 中的 detailItem (只需删除它,因为它已经调用 didSet detailItem):

override func viewDidLoad() {
    super.viewDidLoad()


    var detailDefaultItem = Descriptor()
    // set/configure needed default values in `Descriptor` class or here below
    // detailDefaultItem.property = someValue
    // ...
    detailItem = detailDefaultItem
    // configureView()
...
}