IBOutlet nihil, tetapi terhubung di storyboard, Swift

102

Menggunakan Swift 1.1 dan Xcode 6.2.

Saya memiliki UIStoryboard yang berisi UIViewControllersubclass kustom tunggal . Di atasnya, saya memiliki @IBOutletkoneksi tipe UIViewdari pengontrol itu ke UIView subclass di storyboard. Saya juga memiliki saluran serupa untuk subview dari pandangan itu. Lihat gambar A.

Tetapi pada waktu berjalan, properti ini nihil (Gambar B). Meskipun saya telah meyakinkan saya telah menghubungkan outlet di Interface Builder.

Pikiran :

  • Apakah mungkin karena saya menggunakan subclass dari subclass ada yang salah dengan inisialisasi? Saya tidak menimpa penginisialisasi apa pun
  • awakeFromNib: tidak dipanggil karena alasan tertentu
  • Mungkin itu tidak terhubung ke subview di subview

Hal yang telah saya coba:

  • @IBOutletJenis item yang cocok dan storyboard persis (bukan UIView)
  • Menghapus properti dan outlet dan menambahkannya kembali

Gambar A

Gambar A *

Gambar B

Gambar B

* Kode yang dikaburkan Figure Aadalah:

@IBOutlet private var annotationOptionsView: UIView!
@IBOutlet private var arrivingLeavingSwitch: UISegmentedControl!

Terima kasih.

Stefan Arambasich
sumber
Mengapa tidak mengubah! kepada?
clearView nihil karena tidak ditautkan ke storyboard (lihat lingkaran di sebelah kiri kode dengan lubang, yang menunjukkan bahwa tidak ditautkan), di screenshot saya tidak bisa melihat deklarasi annotationOptionView.
Javier Flores Font
@JavierFloresFont: clearViewSaya berharap menjadi nol. Ini adalah sesuatu yang belum saya refactor. Lihat juga catatan kaki untuk gambar A. @ShaanSingh Seharusnya! karena koneksi dari storyboard (seharusnya) disetel pada waktu proses dan tidak boleh nol.
Stefan Arambasich
Bagaimana pengontrol tampilan ini dimuat? Tunjukkan kepada kami kode yang memintanya, atau jelaskan segue yang terhubung dengannya.
merampok mayoff
1
Mendapatkan storyboard yang tepat: let vc = UIStoryboard(name: "LocationPickerModal", bundle: nil) .instantiateViewControllerWithIdentifier("LocationPickerModalViewController") as LocationPickerModalViewController
Stefan Arambasich

Jawaban:

146

Biasanya ini terjadi karena pengontrol tampilan Anda belum memuat hierarki tampilannya. Pengontrol tampilan hanya memuat hierarki tampilan saat ada sesuatu yang mengirimkan viewpesan kepadanya . Sistem melakukan ini saat tiba waktunya untuk benar-benar meletakkan hierarki tampilan di layar, yang terjadi setelah hal-hal seperti prepareForSegue:sender:dan viewWillAppear:telah kembali.

Karena VC Anda belum memuat hierarki tampilan, outlet Anda masih nihil.

Anda dapat memaksa VC untuk memuat hierarki tampilannya dengan mengatakan _ = self.view.

merampok mayoff
sumber
4
Ini terjadi ketika viewWillAppear:dipanggil, pertama kali saya melakukan sesuatu dengan outlet itu. Mengakses tampilan tidak melakukan apa pun untuk saya. Masih nihil.
Stefan Arambasich
Terima kasih! Ini berhasil juga untuk saya. var v = viewcontroller.view; dipaksa untuk memuat hierarki tampilan. Trik kecil yang bagus! ;)
Yordi Uytersprot
@YordiUytersprot di mana Anda akan meletakkan baris ini?
Async-
4
Nah, jika Anda membuat instance viewcontroller: let vc = self.storyboard? .InstantianteViewControllerWithIdentifier ("StoryboardIDfromVC") sebagai? CustomVC; biarkan view = vc.view; // Sekarang, Anda dapat mengakses IBOutlets dari CustomVC di sini .. vc.customTextField.text = "Lalala"; Semoga membantu Anda! :)
Yordi Uytersprot
4
UIViewcontroller.loadViewIfNeeded()adalah metode yang tepat untuk digunakan di sini.
orkoden
27

Sudahkah Anda mencoba menjalankan Product> Clean. Memecahkan masalah yang sangat mirip untuk saya.

ThottChief
sumber
Aku melakukannya. Maaf, dimaksudkan untuk menandai jawaban saya. Ini hanya mulai berfungsi setelah saya menghapus DerivedDatafolder untuk proyek tersebut.
Stefan Arambasich
3
Hanya dua gerai saya di tengah hierarki tampilan saya yang nihil .. Produk -> Bersih berhasil untuk saya!
Rikco
1
obj c, hanya membersihkan proyek yang berhasil untuk saya ... tidak percaya menghabiskan lebih dari satu jam dan bahkan tidak berpikir untuk membersihkan proyek: / tapi terima kasih !!
rumah kaca
Just Product -> Clean tidak bekerja untuk saya, tetapi saya memulai simulator yang berbeda dan berhasil, jadi pasti ada yang salah di folder DerivedData juga.
berakhir
22

Apakah Anda memberi contoh pengontrol tampilan Anda dari Storyboard atau NIB, atau apakah Anda memberi contoh langsung melalui penginisialisasi?

Jika Anda membuat instance kelas Anda langsung dengan penginisialisasi, outlet tidak akan terhubung. Interface Builder membuat instance yang disesuaikan dari kelas Anda dan mengenkode instance tersebut ke dalam NIB dan Storyboards untuk decoding berulang, itu tidak menentukan kelas itu sendiri. Jika ini adalah masalah Anda, Anda hanya perlu mengubah kode tempat Anda membuat pengontrol untuk menggunakan metode di UIStoryboard, atau UINib.

Jon Hess
sumber
2
Saya membuat sebuah UIStoryboardinstance dan memanggilnya instantiateViewControllerWithIdentifier.
Stefan Arambasich
15

Papan cerita tidak mengenali hal-hal UI lebih lanjut yang saya tambahkan ke dalamnya. Pada waktu berjalan semua referensi nihil. Jadi saya membersihkan folder data turunan saya dan kemudian koneksi tersebut berfungsi kembali.

Stefan Arambasich
sumber
2
Inilah jawabannya. Saya melawan ini cukup lama, membersihkan folder build dan semuanya. Dalam kasus saya, di viewDidLoad()semua koneksi dibuat, tetapi di viewWillAppear()hampir semuanya nil(terkadang satu atau dua masih terhubung). Saya mencoba segalanya dan akhirnya menghapus folder data turunan, membangun kembali, dan semuanya baik-baik saja.
ruttopia
6
Bahkan setelah 3 tahun, Xcode 9.2 masih memiliki bug sialan yang sama. Terima kasih banyak.
Kemal Can Kaynak
1
Di sini untuk melaporkan bahwa ini masih ada di Xcode 11. :(
menghabiskan
13

Ini terjadi pada saya dengan sel tampilan koleksi kustom saya. Ternyata saya harus mengganti metode registerClassforReuseIdentifier saya dengan registerNib. Itu memperbaikinya untuk saya.

rounak
sumber
Kamu benar. Saya membaca konten penghitungan ARC dalam Bahasa Pemrograman Swift secara detail. Saya tidak dapat menemukan alasannya, mengapa properti lemah IBOutlet masih menjadi nihil. Akhirnya, saya mencari '@IBOutlet swift nil' di Google dan menemukan jawaban Anda di SO. Lalu saya menandai garis Xcode template yang ditambahkan 'self.collectionView! .RegisterClass' di viewDidLoad. Kemudian, itu berhasil. Anda menyelamatkan hidup saya.
charles.cc.hsu
12

Ini terjadi pada saya karena saya secara tidak sengaja memberi contoh pengontrol tampilan saya secara langsung alih-alih memberi contoh melalui papan cerita. Jika Anda memberi contoh langsung melalui MyViewController()maka outlet tidak akan terhubung.

Eric Conner
sumber
Jika Anda menggunakan file XIB, instantiate langsung masih berhasil.
Luat Vu Dinh
11

Dalam kasus saya, itu terjadi karena saya mengganti loadViewmetode di subkelas ViewController saya, tetapi lupa menambahkan[super loadView]

-(void)loadView {
// blank
}

Saat Anda mengganti loadViewmetode ini, Anda bertanggung jawab untuk memulai subview Anda. Karena Anda menimpanya, tampilan dari pembuat antarmuka tidak berkesempatan untuk dikonversi ke objek kakao dan dengan demikian outlet tetap nihil.

Jika Anda mengimplementasikan loadView di subkelas pengontrol tampilan, Anda bertanggung jawab untuk memuat elemen UI dari storyboard / xib ke dalam kode.

Atau panggil saja

[super loadView];

Sehingga superclass mendapat kesempatan untuk memuat storyboard / xib ke dalam kode.

zinnuree
sumber
8

Anda dapat memanggil controller.viewuntuk memaksa memuat tampilan guna menginisialisasi IBOutlets, lalu Anda akan dapat menetapkan nilainya.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if (segue.identifier == "identifier") {
        let controller = segue.destinationViewController as! YourController
        let _ = controller.view //force to load the view to initialize the IBOutlets

        controller.your_IBOutlet_property = xxx
        ...
        controller.delegate = self
    }
}
zs2020
sumber
7

Jika Anda membuat instance view controllermelalui programatis. Kemudian coba buat seperti di bawah ini

let initialVC = self.storyboard?.instantiateViewController(withIdentifier: "InitialVC") as! InitialVC

bukannya secara langsung

let initialVC = InitialVC()

Ini berhasil untuk saya.

Vinoth Vino
sumber
6

Bagi saya, ini terjadi ketika saya secara tidak sengaja mendeklarasikan kelas pengontrol tampilan saya sebagai

class XYZViewController: UINavigationController {
}

(yaitu sebagai UINavigationControllerbukan a UIViewController).

Xcode tidak menangkap kesalahan ini, kelas tampaknya membangun baik, dan fungsi override seperti viewDidLoad, viewWillAppear, dll semua bekerja dengan benar. Tapi tidak ada satupun yang IBOutletterhubung.

Mengubah deklarasi menjadi

class XYZViewController: UIViewController {
}

memperbaikinya sepenuhnya.

HughHughTeotl
sumber
5

Saya mengalami masalah ini baru-baru ini! Inilah pikiran saya. Masalahnya bukan tentang storyboard Anda atau masalah tautan apa pun. Ini tentang bagaimana Anda memulai ViewController Anda. Terutama saat Anda menggunakan Swift. (Hampir tidak ada apa pun di editor saat Anda membuat file kelas)

Dengan hanya menggunakan init()dari kelas super tidak dapat memulai apa pun yang Anda kerjakan dengan papan cerita. Jadi yang perlu Anda lakukan adalah mengubah inisialisasi ViewController. Replace let XXViewController = XXViewController() by let XXViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("XXViewController") as! XXViewController This memberi tahu program untuk pergi ke storyboard menemukan XXViewController dan memulai semuanya IBOutletdi storyboard Anda.

Semoga bantuan ini ~ GL

pengguna3882355
sumber
Bukan itu masalahnya
Stefan Arambasich
4

2019, SATU KEMUNGKINAN UNTUK MASALAH MENGERIKAN INI:

  • Katakanlah Anda mungkin memiliki tampilan kontainer yang menunjukkan semacam jam. Jadi kamu punya

    Kelas Jam: UIViewController

Anda benar-benar menggunakannya di sejumlah tempat di aplikasi .

Di layar utama, di layar detail, di layar edit.

Anda memiliki aplikasi modern seperti snapchat yang rumit.

Bahkan, Clocksebenarnya bisa dimuat lebih dari sekali pada waktu yang bersamaan suatu tempat di layar yang sama . (Mungkin tersembunyi dalam beberapa kasus.)

Anda mulai mengerjakan satu contoh Clockdi salah satu dari banyak papan cerita Anda.

Di papan cerita itu Anda menambahkan label, Label Baru.

Biasanya Anda menambahkan outlet dalam kode. Semuanya harus bekerja. Semua gerai lainnya bekerja dengan sempurna.

Anda pasti punya menautkan outletnya.

Tapi aplikasi macet dengan NewLabel sebagai nihil.

Xcode dengan jelas memberi tahu Anda "Anda lupa menghubungkan stopkontak".

Alasannya adalah ini ......... Anda hanya memiliki "Label Baru" di satu satu storyboard yang menggunakan Jam!

Kecelakaan itu sebenarnya dari >>> tempat lain <<<< Anda menggunakan Jam !!!!

Xcode tidak memberi tahu Anda bahwa kecelakaan itu berasal dari tempat lain sama sekali, bukan dari tempat Anda bekerja!

Kecelakaan itu sebenarnya bukan dari tempat Anda bekerja - melainkan dari tempat lain storyboard , di mana tidak ada item "Label Baru" di storyboard itu !!!

Membuat frustrasi.

Gendut
sumber
3

Untuk Swift 3.

func configureView() {
    let _  = self.view
}
prog_24
sumber
2

Anda perlu memuat hierarki tampilan terlebih dahulu untuk membuat instance outlet di storyboard. Untuk ini, Anda bisa memanggil metode loadView atau loadViewIfNeeded secara manual.

maven25
sumber
2

Dalam kasus saya, aplikasi tiba-tiba mulai mogok. Debugging itu mengungkapkan bahwa semua outlet masih nilpada saat itu viewDidLoad().

Aplikasi saya masih menggunakan ujung pena (bukan papan cerita) untuk sebagian besar pengontrol tampilan. Semuanya ada di tempatnya, semua outlet terhubung dengan benar. Saya memeriksa ulang.

Kami biasanya memberi contoh pengontrol tampilan kami sebagai

let newVC = MYCustomViewController()

... yang karena alasan tertentu tampaknya berfungsi selama .xib dinamai sama dengan kelas pengontrol tampilan (meskipun tidak yakin bagaimana cara kerjanya. tidak memanggil init(nibName:bundle:)dengan argumen nil, atau menimpa init()untuk melakukannya padaself seperti itu biasanya disarankan ...).

Jadi saya mencoba menelepon secara eksplisit

 let newVC = MYCustomViewController(nibName: "MYCustomViewController", bundle: .main)

... hanya untuk disambut dengan kesalahan pengecualian waktu proses:

*** Menghentikan aplikasi karena pengecualian yang tidak tertangkap 'NSInternalInconsistencyException', alasan: 'Tidak dapat memuat NIB dalam paket:' NSBundle </ Users / nicolasmiari / Library / Developer / CoreSimulator / Devices / 3DA3CF21-108D-498F-9649-C4FC9E3C1A8D / data /Containers/Bundle/Application/C543DDC1-AE86-4D29-988C-9CCE89E23543/MyApp.app> (dimuat) 'dengan nama' MYCustomViewController ''

Dan kemudian , saya melihatnya:

Kotak centang "Target Keanggotaan" dari file .xib tidak dicentang.


Pasti terjadi saat menyelesaikan salah satu konflik penggabungan yang sering terjadi terkait file proyek Xcode.

Apple pasti perlu menghadirkan format file proyek yang lebih ramah SCM.

Nicolas Miari
sumber
2

Solusi kerja 100% untuk membuat ViewControllers dari XIB tanpa StoryBoards

  1. Buat kelas CustomViewController: UIViewController
  2. Buat tampilan CustomViewControllerView.xib
  3. Di CustomViewControllerView.xib di Interface Builder pilih Placeholder -> File's Owner
  4. Dalam "Attributes inspector", setel Kelas ke CustomViewController
  5. Dalam "Connections inspector" menghubungkan "tampilan" ke tampilan tingkat atas dari xib (pastikan Kelas tampilan tingkat atas tidak mengarah ke CustomViewController)
  6. Di "Connections inspector", hubungkan outlet lain (jika perlu / ada)
  7. Buat instance CustomViewController di pengontrol tampilan induk / Delegasi aplikasi

7.1.

// creating instance
let controller = CustomViewController()

7.2.

// connecting view/xib with controller instance
let bundle = Bundle(for: type(of: controller))
bundle.loadNibNamed("CustomViewControllerView", owner: controller, options: nil)

7.3.

// get/set outlets
controller.labelOutlet.text = "title"
controller.imageOutlet.image = UIImage(named: "image1")
Roman M
sumber
Jawaban yang fantastis, terima kasih! Untuk mengetahui nilainya, Anda juga dapat mengganti init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)dan memanggil langkah 7.2 dengan selflangsung di kelas CustomViewController.
brandonscript
1

Periksa koneksi IBOutlet Anda jika terhubung ke Pemilik file atau tampilan. Mungkin ada kesalahan.

Ahd Radwan
sumber
1

Kasus lain:

Outlet Anda tidak akan disetel hingga tampilan pengontrol tampilan benar-benar dibuat, yang dalam kasus Anda mungkin terjadi tidak lama setelah initWithNibName: bundle: —pada saat itu mereka masih nihil. Setiap pengaturan yang Anda lakukan yang melibatkan outlet tersebut harus terjadi dalam metode -viewDidLoad pengontrol tampilan Anda.

93sauu
sumber
1

Bagi saya, saya memiliki kesalahan yang sama pada storyboard yang dilokalkan, sebuah elemen ditambahkan di beberapa lokal dan tidak di yang lain, jadi saya tidak memiliki referensi untuk elemen itu ketika beralih ke lokal elemen yang hilang, saya harus menghapus pelokalan (redundan) untuk storyboard itu menggunakan https://stackoverflow.com/a/42256341/1356559 .

Amr Lotfy
sumber
1

Bagi saya, ini mengecewakan karena containerViewnihil.

Ini kode saya dengan Crash .

@IBOutlet private var containerView: UIView!  // Connected to Storyboard
override open func loadView() {
    containerView.addSubview(anotherView)
}

Hal yang hilang memanggil super.loadView(). Jadi menambahkannya memecahkan masalah bagi saya.

Kode Tetap :

@IBOutlet private var containerView: UIView!
override open func loadView() {
    super.loadView()
    containerView.addSubview(anotherView)
}
BLC
sumber
Anda tidak boleh memanggil loadView () secara langsung ( developer.apple.com/documentation/uikit/uiviewcontroller/… ), panggil self.view sebagai gantinya
Lio
1

Saya mengalami masalah serupa ketika saya sebelumnya menambahkan register (_: forCellReuseIdentifier :) untuk sel khusus setelah saya menentukan pengenal di storyboard. Punya kode ini dalam fungsi viewDidLoad (). Setelah saya menghapusnya, itu berfungsi dengan baik.

Gthoma2
sumber
1

Kasus lain yang baru saja saya hadapi. Saya mengubah nama kelas saya untuk UIViewController, tetapi saya lupa mengganti nama file .xib tempat antarmuka dibuat.

Setelah saya menangkap ini dan membuat nama file mencerminkan nama kelas, semuanya baik-baik saja!

Saya harap itu membantu seseorang.

Brian Trzupek
sumber
1

Punya satu lagi ...

Jika Anda memiliki kelas khusus untuk UITableViewCell tetapi lupa untuk menentukan Kustom dalam Gaya sel.

Phantom59
sumber
1

Anda dapat memvalidasi jika tampilan is dimuat.

if isViewLoaded && view.window != nil {
 //self.annotationOptionsView.
}
A. Trejo
sumber
0
  1. pilih keduanya .hdan .mlihat file pengontrol
  2. hapus referensi file tersebut
  3. tambahkan kembali file ke pohon proyek Anda
  4. buka storyboard, lalu buat ulang proyeknya
Sandip Patel - SM
sumber
0

Secara tidak sengaja saya membuat subclass pengontrol tampilan saya dengan AVPlayerViewControlleralih - alih UIViewController. Dengan memutar ulang agar UIViewControllersemuanya kembali normal. Ini akan membantu.

Tidak ada pembersihan build (normal & penuh), menghapus folder data turunan dan keluar dari Xcode berfungsi untuk saya.

Hemang
sumber
0

Saya memiliki masalah yang sama setelah menyalin kelas (ditautkan ke xib) untuk digunakan kembali dengan kelas viewcontroller lain (ditautkan ke storyboard). Saya lupa untuk menghapus

override var nibName

dan

override var nibBundle

metode.

Setelah menghapusnya, outlet saya mulai berfungsi.

smukamuka
sumber
0

Saya melihat Anda menggunakan ViewController!? di ViewControllerkelas Anda harus menggunakan -viewDidLoad, bukan -awakeFromNib , -awakeFromNibdigunakan untuk UIViewkelas

EvGeniy ​​Ilyin
sumber
0

Periksa apakah Anda memiliki outlet yang hilang atau terputus.

masukkan deskripsi gambar di sini

Исмаил Хасбулатов
sumber
0

Jika Anda memiliki dua main.storyboardsdan Anda membuat perubahan ke yang salah, ini bisa terjadi. Ini dapat terjadi kapan pun Anda menghubungkan outlet dari yang tidak berdasar storyboard.

ScottyBlades
sumber