web-dev-qa-db-ja.com

Swift / iOS:ViewControllerをロードした後のIBOutletnil

一部のオブジェクトが2Dボードに表示されるアプリ(XCode 8.2.1)を作成しています。ユーザーがこれらのオブジェクトのいずれかをタップすると、スタイル付きのモーダル情報ボックスとしてそのオブジェクトに関する情報が表示されます。私の設計では、必要に応じて表示する別のViewControllerに情報を書き込むことです。

2番目のViewControllerの基本的なスタブを設計し、InterfaceBuilderでそれに単一のラベルを追加しました。次に、このラベルをカスタムVC class:

_class InfoViewController: UIViewController {
    @IBOutlet weak var info: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    func displayInfo() {
        info.attributedText = NSAttributedString(string: "abc")
    }
}
_

ただし、アプリをテストしてオブジェクトをタップすると、カスタムのviewDidLoad()メソッドでもinfoフィールドはnilになりますVC =クラス。VC)の表示方法は次のとおりです。

_let infoViewController = InfoViewController()
infoViewController.modalPresentationStyle = .overCurrentContext
self.present(infoViewController, animated: true, completion: nil)
infoViewController.displayInfo()
_

(注:最終的には、InfoViewControllerのインスタンスは1つだけになりますが、これはテスト用です。グローバルインスタンスがあると違いが生じるとは思いませんか?)

私が言ったように、それがviewDidLoad()メソッド内であろうとdisplayInfo()メソッド内であろうと、infoは常にnilであり、そのattributedString属性はアプリをクラッシュさせます。 presentメソッドが非同期的に呼び出される可能性があると考えて、displayInfo()の内部からviewDidLoad()を呼び出してみましたが、違いはありませんでした。

IBOutletが正しく初期化されないようにするために、私が忘れたことを誰かに教えてもらえますか?

ありがとう!

ダビデ

7
David

問題は、ストーリーボードシーンに関係なくビューコントローラをインスタンス化するInfoViewController()への参照です。使用したい instantiateViewController

let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true) {
    infoViewController.displayInfo()
}

いくつかの注意事項:

  • これは、(a)ストーリーボードのシーンに「ストーリーボードID」を指定したことを前提としています。 (b)そのシーンの基本クラスをInfoViewControllerに設定しました。

  • displayInfoの完了ハンドラーでpresentを呼び出したのは、シーンが表示されてアウトレットが接続されるまで呼び出されたくないためです。


または、インスタンス化した直後にInfoViewControllerの非アウトレットプロパティを更新し、そのviewDidLoadにそれらのプロパティを取得させて、アウトレットを更新することもできます。例:

class InfoViewController: UIViewController {
    var info: String!
    @IBOutlet weak var infoLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        infoLabel.attributedText = NSAttributedString(string: info)
    }
}

@IBOutlet名をinfoLabelに変更し、Stringというプロパティをinfoに追加したことに注意してください。これは慣例である傾向があり、アウトレットにはコントロールのタイプを示す接尾辞が付いており、Stringプロパティなどのモデルオブジェクトには接尾辞がありません。 (これらのプロパティ名の変更に問題がないように、IBの接続インスペクターでその古いコンセントを削除することを確認する必要があります。)

とにかく、あなたはそれからすることができます:

let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.info = "abc"
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true, completion: nil)

重要な点は、シーンをインスタンス化した直後にシーンのアウトレットを更新しようとしないことですが、これはviewDidLoadが呼び出されるまで延期されるようにしてください。

22
Rob

交換しました

let vc = CCDetailViewController()

あり

let vc = self.storyboard?.instantiateViewController(withIdentifier: "CCDetailViewController")

ついに

self.present(vc!, animated: true, completion: nil)

今それは動作します...

1
iOS Lifee

私の場合、同じクラスの新しいViewControllerを作成しました。ストーリーボードに2つのビューコントローラーが含まれることになりましたが、同じクラスを参照しています。古いViewControllerを削除した後、すべてが正常に機能しました。

それが誰かに役立つことを願っています。

0
Suresh Vutukuru