Значение свойства didSet отображается только в print () - PullRequest
0 голосов
/ 04 мая 2018

НАЧАЛЬНАЯ ЦЕЛЬ :

Иметь представление со списком ячеек, расположенных вертикально, с отображением некоторой информации. Как только пользователь нажимает на ячейку, чтобы показать новое представление с дополнительной информацией.

ДОРОГА ТАК (карри на своенравном сыне!):

  • Я создал 2 контроллера представления: ViewController (создание подклассов UICollectionViewController, UICollectionViewDelegateFlowLayout) и DetailViewController (создание подклассов UIViewController).
  • Я создал Ячейку , которую ViewController использует для генерации представления коллекции, и DetailView , которую DetailViewController использует
  • Я создал структуру с именем Detail в качестве пользовательского типа данных, который обеспечивает хранение данных с использованием свойств (например, имя, фамилия, адрес и т. Д.)

Структура:

struct Detail: Decodable {
    let name: String?
    let surname: String?
    let address: String?
    let description: String?
}

Я использую следующие данные для тестирования (после завершения тестирования я получу эти данные из вызова API). Я поместил его внутри ViewController :

let details: [Detail] = [Detail(name: "Chris", surname: "Doe", address: "Neverland 31", description: "This is a description about Chris Doe"), Detail(name: "Tony", surname: "Cross", address: "Galaxy Road 1", description: "This is a description about Tony Cross")]

Для создания ячеек используйте информацию выше и метод:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

А также:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! Cell

Поскольку метод требует, чтобы мы возвращали UICollectionViewCell, я сначала отправляю связанную информацию в Cell, выполняя следующие действия:

cell.details = details[indexPath.item]
return cell

Внутри ячейки Я создал следующее свойство, используя didSet , чтобы помочь мне получить информацию:

var details: Detail? {
    didSet {
        guard let details = details else { return }
        guard let name = details.name else { return }
        ....
        ....
     }    

Как вы понимаете, используя информацию, поступающую из ViewController, я динамически создавал каждую ячейку.

В этот момент все было хорошо.

Затем я попытался показать подробный вид при нажатии на ячейку. Для этого я следовал той же практике внутри метода:

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    let detailView = DetailView()
    detailView.details = details[indexPath.item]

    let detailViewController = DetailViewController()
    detailViewController.modalTransitionStyle = .coverVertical
    self.present(detailViewController, animated: true, completion: nil)
}

Опять же, в DetailView Я использую тот же подход, чтобы получить данные, связанные с выбранным элементом. Таким образом, я могу получить доступ к данным ячейки, выбранной пользователем, как показано ниже:

 import UIKit

 class DetailView: UIView {

     var dismissDetailViewAction: (() -> Void)?

     var details: Detail? {
        didSet {

            // get details
            guard let details = details else { return }
            guard let name = details.name else { return }
            guard let surname = details.surname else { return }
            guard let address = details.address else { return }
            guard let description = details.description else { return }

            // print description and it shows in the console but not in the view
            print(description)

            let attributedTextDescription = NSMutableAttributedString(string: description, attributes: [NSAttributedStringKey.font: UIFont.FontBook.AvertaRegular.of(size: 20), NSAttributedStringKey.foregroundColor: UIColor.white])
            briefDescription.attributedText = attributedTextDescription
            briefDescription.textAlignment = .center
            briefDescription.textColor = .white
            briefDescription.numberOfLines = 0
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        setupView()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not yet been implemented")
    }

    fileprivate func setupView() {
        setupDescriptionText()
        setupCloseButton()
    }

    let briefDescription: UITextView = {
        let text = UITextView()          
        text.textColor = .red
        return text
    }()

    let closeButton: UIButton = {
        let button = UIButton(title: "Close", font: UIFont.FontBook.AvertaRegular.of(size: 18), textColor: .white, cornerRadius: 5)
        button.backgroundColor = .black
        button.addTarget(self, action: #selector(closeDetailView), for: .touchUpInside)
        return button
    }()


    fileprivate func setupDescriptionText() {
        self.addSubview(briefDescription)
        briefDescription.translatesAutoresizingMaskIntoConstraints = false
        briefDescription.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5).isActive = true
        briefDescription.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -5).isActive = true
        briefDescription.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
        briefDescription.heightAnchor.constraint(equalToConstant: 300).isActive = true
    }

    fileprivate func setupCloseButton() {
        self.addSubview(closeButton)
        closeButton.translatesAutoresizingMaskIntoConstraints = false

        closeButton.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        closeButton.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
        closeButton.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 40).isActive = true
        closeButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -40).isActive = true
        closeButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
    }

    @objc func closeDetailView() {
        dismissDetailViewAction?()
    }

}

Итак, что я на самом деле делаю, так это разрабатываю статическую часть представления вне didSet, и что такое динамическая часть внутри didSet. Это работает с ячейками collectionView.

Я использую DetailViewController , чтобы отобразить DetailView и отключить себя, когда пользователь нажимает кнопку «Закрыть».

import UIKit

class DetailViewController: UIViewController {

    // reference DetailView view
    var detailView: DetailView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // setup view elements
        setupView()
    }

    fileprivate func setupView() {
        let mainView = DetailView(frame: self.view.frame)
        self.detailView = mainView
        self.view.addSubview(detailView)

        self.homeDetailView.dismissDetailViewAction = dismissDetailView

        // pin view
        self.detailView.translatesAutoresizingMaskIntoConstraints = false
        self.detailView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        self.detailView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        self.detailView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        self.detailView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
    }

    fileprivate func dismissDetailView() {
        // dismiss current (DetailViewController) controller
        self.dismiss(animated: true, completion: nil)
    }
}

Причина, по которой я это сделал, заключается в том, что мне нравится поддерживать свои ViewControllers как можно более чистыми (Massive View Controller, а не мое).

ПРОБЛЕМА

Все построено без проблем, но когда я щелкаю ячейку, чтобы перейти к DetailView, информация не отображается.

странная часть

Внутри DetailView -> didSet, когда я использую print (name), он работает просто отлично (вы видите правильное имя в консоли). Но когда я пытаюсь использовать это значение внутри представления, оно не будет отображаться.

И я знаю, что мой DetailView в порядке, так как, если я использую в нем жестко закодированные значения, он работает (вы видите правильный результат).

Любой совет, почему это не работает должным образом?

PS: Я строю все это программно. Раскадровки не задействованы.

Заранее спасибо и извините за потерянный пост.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Как уже упоминалось, ваш detailView не указан внутри detailViewController. Вместо этого вы создаете еще один экземпляр DetailView внутри DetailViewController, но в этом нет Detail.

Консольное сообщение было вызвано изнутри вашего detailView, но внутри detailViewController есть еще один экземпляр, который не вызывал это сообщение, потому что его Detail по умолчанию имеет значение nil.

Чтобы быть кратким, чтобы исправить это, вы должны просто сделать следующие изменения:

import UIKit

class DetailViewController: UIViewController {

var detail: Detail!

private lazy var detailView: DetailView = {
    let mainView = DetailView(frame: self.view.frame)
    mainView.details = detail
    return mainView
}

override func viewDidLoad() {
    super.viewDidLoad()

    setupView()
}

fileprivate func setupView() {
    self.view.addSubview(detailView)

    self.homeDetailView.dismissDetailViewAction = dismissDetailView

    // pin view
    self.detailView.translatesAutoresizingMaskIntoConstraints = false
    self.detailView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
    self.detailView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
    self.detailView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
    self.detailView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
}

fileprivate func dismissDetailView() {
    // dismiss current (DetailViewController) controller
    self.dismiss(animated: true, completion: nil)
}

}

А внутри вашего collectionView(...) func:

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let detailViewController = DetailViewController()
    detailViewController.detail = details[indexPath.item]
    detailViewController.modalTransitionStyle = .coverVertical
    self.present(detailViewController, animated: true, completion: nil)
}
0 голосов
/ 04 мая 2018
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    let detailView = DetailView()
    detailView.details = details[indexPath.item]

    let detailViewController = DetailViewController()
    detailViewController.modalTransitionStyle = .coverVertical
    self.present(detailViewController, animated: true, completion: nil)
}

Вы делаете DetailView здесь, передаете его details ... и затем ничего не делаете с ним.

Обычно DetailView будет свойством DetailViewController, и вы передадите details в контроллер представления, который отобразит его.

Здесь происходит то, что вы создаете, настраиваете и выбрасываете DetailView, когда вам, вероятно, следует использовать тот, который DetailViewController владеет или должен принадлежать.

...