Bagaimana cara menjebak UIViewAlertForUnsatisfiableConstraints?

234

Saya melihat kesalahan muncul di log debugger saya:

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x191f0920 H:[MPKnockoutButton:0x17a876b0]-(34)-[MPDetailSlider:0x17a8bc50](LTR)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Bagaimana cara saya menjebak panggilan itu? Tidak muncul di mana pun dalam kode saya.

Tangkapan Layar1

Maury Markowitz
sumber
Dalam 9 dari 10 kasus: ini hanya disebabkan oleh: untuk beberapa tampilan atau item di storyboard yoru, Anda hapus centang "Terpasang". (Misalnya, hanya tombol pengembangan atau sesuatu yang tidak Anda perlukan lagi.) Secara umum, ini menangani "tidak diinstal" dengan buruk: sering meninggalkan kendala di sana yang menjadi tidak berarti tanpa item yang tidak diinstal. Seringkali solusinya adalah dengan menghapus item yang sudah Anda lupakan, yang ada di sekitar "not-Installed" - cukup hapus saja.
Fattie

Jawaban:

442

Posting ini membantu saya BANYAK !

Saya menambahkan breakpoint simbolik UIViewAlertForUnsatisfiableConstraints dengan tindakan yang disarankan:

Proyek Obj-C

po [[UIWindow keyWindow] _autolayoutTrace]

Breakpoint simbolik dengan tindakan kustom di proyek Objective-C

Proyek cepat

expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace]

Breakpoint simbolis dengan tindakan khusus

Dengan petunjuk ini, log menjadi lebih terperinci, dan Lebih mudah bagi saya untuk mengidentifikasi pandangan mana yang memiliki kendala.

UIWindow:0x7f88a8e4a4a0
|   UILayoutContainerView:0x7f88a8f23b70
|   |   UINavigationTransitionView:0x7f88a8ca1970
|   |   |   UIViewControllerWrapperView:0x7f88a8f2aab0
|   |   |   |   UIView:0x7f88a8ca2880
|   |   |   |   |   *UIView:0x7f88a8ca2a10
|   |   |   |   |   |   *UIButton:0x7f88a8c98820'Archived'
|   |   |   |   |   |   |   UIButtonLabel:0x7f88a8cb0e30'Archived'
|   |   |   |   |   |   *UIButton:0x7f88a8ca22d0'Download'
|   |   |   |   |   |   |   UIButtonLabel:0x7f88a8cb04e0'Download'
|   |   |   |   |   |   *UIButton:0x7f88a8ca1580'Deleted'
|   |   |   |   |   |   |   UIButtonLabel:0x7f88a8caf100'Deleted'
|   |   |   |   |   *UIView:0x7f88a8ca33e0
|   |   |   |   |   *_UILayoutGuide:0x7f88a8ca35b0
|   |   |   |   |   *_UILayoutGuide:0x7f88a8ca4090
|   |   |   |   |   _UIPageViewControllerContentView:0x7f88a8f1a390
|   |   |   |   |   |   _UIQueuingScrollView:0x7f88aa031c00
|   |   |   |   |   |   |   UIView:0x7f88a8f38070
|   |   |   |   |   |   |   UIView:0x7f88a8f381e0
|   |   |   |   |   |   |   |   UIView:0x7f88a8f39fa0, MISSING HOST CONSTRAINTS
|   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8cb9bf0'Retrieve data'- AMBIGUOUS LAYOUT for UIButton:0x7f88a8cb9bf0'Retrieve data'.minX{id: 170}, UIButton:0x7f88a8cb9bf0'Retrieve data'.minY{id: 171}
|   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8f3ad80- AMBIGUOUS LAYOUT for UIImageView:0x7f88a8f3ad80.minX{id: 172}, UIImageView:0x7f88a8f3ad80.minY{id: 173}
|   |   |   |   |   |   |   |   |   *App.RecordInfoView:0x7f88a8cbe530- AMBIGUOUS LAYOUT for App.RecordInfoView:0x7f88a8cbe530.minX{id: 174}, App.RecordInfoView:0x7f88a8cbe530.minY{id: 175}, App.RecordInfoView:0x7f88a8cbe530.Width{id: 176}, App.RecordInfoView:0x7f88a8cbe530.Height{id: 177}
|   |   |   |   |   |   |   |   |   |   +UIView:0x7f88a8cc1d30- AMBIGUOUS LAYOUT for UIView:0x7f88a8cc1d30.minX{id: 178}, UIView:0x7f88a8cc1d30.minY{id: 179}, UIView:0x7f88a8cc1d30.Width{id: 180}, UIView:0x7f88a8cc1d30.Height{id: 181}
|   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8cc1ec0- AMBIGUOUS LAYOUT for UIView:0x7f88a8cc1ec0.minX{id: 153}, UIView:0x7f88a8cc1ec0.minY{id: 151}, UIView:0x7f88a8cc1ec0.Width{id: 154}, UIView:0x7f88a8cc1ec0.Height{id: 165}
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e68e10- AMBIGUOUS LAYOUT for UIView:0x7f88a8e68e10.minX{id: 155}, UIView:0x7f88a8e68e10.minY{id: 150}, UIView:0x7f88a8e68e10.Width{id: 156}
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e65de0- AMBIGUOUS LAYOUT for UIImageView:0x7f88a8e65de0.minX{id: 159}, UIImageView:0x7f88a8e65de0.minY{id: 182}
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8e69080'8-6-2015'- AMBIGUOUS LAYOUT for UILabel:0x7f88a8e69080'8-6-2015'.minX{id: 183}, UILabel:0x7f88a8e69080'8-6-2015'.minY{id: 184}, UILabel:0x7f88a8e69080'8-6-2015'.Width{id: 185}
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0690'16:34'- AMBIGUOUS LAYOUT for UILabel:0x7f88a8cc0690'16:34'.minX{id: 186}, UILabel:0x7f88a8cc0690'16:34'.minY{id: 187}, UILabel:0x7f88a8cc0690'16:34'.Width{id: 188}, UILabel:0x7f88a8cc0690'16:34'.Height{id: 189}
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8cc2050- AMBIGUOUS LAYOUT for UIView:0x7f88a8cc2050.minX{id: 161}, UIView:0x7f88a8cc2050.minY{id: 166}, UIView:0x7f88a8cc2050.Width{id: 163}
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e69d90- AMBIGUOUS LAYOUT for UIImageView:0x7f88a8e69d90.minX{id: 190}, UIImageView:0x7f88a8e69d90.minY{id: 191}, UIImageView:0x7f88a8e69d90.Width{id: 192}, UIImageView:0x7f88a8e69d90.Height{id: 193}
|   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3cc00
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e618d0
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e5ba10
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3cd70
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e58e10
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e5e7a0
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3cee0
|   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3dc70
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e64dd0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8e65290'Average flow rate'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8e712d0'177.0 ml/s'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8c97150'1299.4'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3dde0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3df50'Maximum flow rate'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cbfdb0'371.6 ml/s'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0230'873.5'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3e2a0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3e410'Total volume'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0f20'371.6 ml'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3e870
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3ea00'Time do max. flow'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0ac0'3.6 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3ee10
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3efa0'Flow time'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cbf980'2.1 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3f3e0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3f570'Voiding time'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc17e0'3.5 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3f9a0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3fb30'Voiding delay'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc1380'1.0 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e65000
|   |   |   |   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8e52f20'Show'
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e6e1d0
|   |   |   |   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8e52c90'Send'
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e61bb0
|   |   |   |   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8e528e0'Delete'
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e6b3f0
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3ff60
|   |   |   |   |   |   |   |   |   *UIActivityIndicatorView:0x7f88a8cba080
|   |   |   |   |   |   |   |   |   |   UIImageView:0x7f88a8cba700
|   |   |   |   |   |   |   |   |   *_UILayoutGuide:0x7f88a8cc3150
|   |   |   |   |   |   |   |   |   *_UILayoutGuide:0x7f88a8cc3b10
|   |   |   |   |   |   |   UIView:0x7f88a8f339c0
|   |   UINavigationBar:0x7f88a8c96810
|   |   |   _UINavigationBarBackground:0x7f88a8e45c00
|   |   |   |   UIImageView:0x7f88a8e46410
|   |   |   UINavigationItemView:0x7f88a8c97520'App'
|   |   |   |   UILabel:0x7f88a8c97cc0'App'
|   |   |   UINavigationButton:0x7f88a8e3e850
|   |   |   |   UIImageView:0x7f88a8e445b0
|   |   |   _UINavigationBarBackIndicatorView:0x7f88a8f2b530

Legend:
    * - is laid out with auto layout
    + - is laid out manually, but is represented in the layout engine because translatesAutoresizingMaskIntoConstraints = YES
     - layout engine host

Kemudian saya menghentikan eksekusi Berhenti sebentar dan saya mengubah warna latar belakang tampilan bermasalah dengan perintah (mengganti 0x7f88a8cc2050dengan alamat memori objek Anda tentu saja) ...

Obj-C

expr ((UIView *)0x7f88a8cc2050).backgroundColor = [UIColor redColor]

Swift 3.0

expr -l Swift -- import UIKit
expr -l Swift -- unsafeBitCast(0x7f88a8cc2050, to: UIView.self).backgroundColor = UIColor.red

... dan hasilnya Luar Biasa!

Lihat Petunjuk

Sangat menakjubkan! Semoga ini bisa membantu.

Thomás Calmon
sumber
3
@iAnurag Anda dapat menjalankan perintah di area konsol, saat eksekusi dijeda.
Thomás Calmon
2
@ TomCalmon Saya melakukan hal yang sama ... tetapi menunjukkan kesalahan berikut rror: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x7f88a8cc2050). The process has been returned to the state before expression evaluation.
iAnurag
2
expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace]kembali niluntuk saya
Igor Andreev
2
Pastikan Anda mengganti 0x7f88a8cc2050 dengan alamat memori objek Anda dan jalankan perintah di konsol saat eksekusi dijeda.
Tom Howard
3
Sulit dipercaya. Tip besar di sini, benar-benar membantu saya langsung ke masalah ini. Setelah item diubah menjadi merah, lanjutkan eksekusi jika memungkinkan dan Anda akan melihat sorotan.
Aaron
255

Anda ingin menambahkan Symbolic Breakpoint. Apple memberikan panduan yang sangat baik tentang cara melakukan ini.

  1. Buka Breakpoint Navigator cmd+7( cmd+8dalam Xcode 9)
  2. Klik Addtombol di kiri bawah
  3. Pilih Add Symbolic Breakpoint...
  4. Di mana dikatakan Symbolketik sajaUIViewAlertForUnsatisfiableConstraints

Anda juga dapat memperlakukannya seperti breakpoint lainnya, menyalakan dan mematikannya, menambahkan tindakan, atau mencatat pesan.

Stephen Furlani
sumber
55
Saya hanya tidak mengerti bagaimana saya bisa men-debug masalah dengan lebih baik dengan petunjuk ini. Saya menambahkan breakpoint simbolis tetapi masih tidak memberi saya cukup informasi apa masalahnya. Satu-satunya cara adalah mencoba membaca baris demi baris dan memahami apa yang menyebabkan masalah .... jika tidak, selesaikan kendala dan tambahkan lagi bersama dengan Pratinjau dalam tampilan asissten akan sangat membantu!
Alex Cio
11
Ini mungkin membantu untuk mendapatkan info lebih lanjut setelah berhenti di breakpoint: staxmanade.com/2015/06/debugging-ios-autolayout-issues
fabb
1
Hanya menambahkan bahwa Anda sekarang dapat memberikan pengidentifikasi kendala secara langsung di IB sehingga ketika Anda men-debug mereka, itulah nama yang akan Anda lihat.
Mark A. Donohoe
2
(tindak lanjut pada @MarqueIV) NSLayoutConstrainttelah memiliki identifierproperti sejak iOS 7 - Xcode 7 ke atas , yang dapat diatur baik dari IB Storyboards maupun dari kode. Dengan mengatur pengenal Anda dapat lebih mudah membedakan antara yang dihasilkan oleh sistem dan yang dihasilkan oleh pengguna di log debug, misalnya myConstraint.identifier = "centered image"(sumber & contoh: useyourloaf.com/blog/using-identifiers-to-debug-autolayout )
PDK
@AlexCio Bagaimana ini membantu? Paling tidak itu berhenti pada saat itu terjadi. Ini memberikan jejak tumpukan di mana Anda dapat mundur dan menemukan asal ...
Honey
10

Ikuti saran Stephen dan mencoba men-debug kode dan whoa! itu berhasil. Jawabannya terletak pada pesan debug itu sendiri.

Will attempt to recover by breaking constraint NSLayoutConstraint:0x191f0920 H:[MPKnockoutButton:0x17a876b0]-(34)-[MPDetailSlider:0x17a8bc50](LTR)>

Baris di atas memberi tahu Anda bahwa runtime berfungsi dengan menghapus batasan ini. Mungkin Anda tidak perlu Horizontal Spacing pada tombol Anda (MPKnockoutButton). Setelah Anda menghapus batasan ini, itu tidak akan mengeluh saat runtime & Anda akan mendapatkan perilaku yang diinginkan.

Kelompok
sumber
3
Kompiler? Maksudmu runtime? Kompiler tidak menghapus kendala. Compiler membiarkannya di sana untuk berurusan dengan runtime, karenanya "memulihkan dengan melanggar batasan" selama runtime .
drhr
Ya yang saya maksud runtime
Sategroup
2

Setiap kali saya mencoba untuk menghilangkan kendala yang harus dilanggar oleh sistem, kendala saya tidak lagi cukup untuk memenuhi IB (yaitu "kendala yang hilang" muncul di IB, yang berarti mereka tidak lengkap dan tidak akan digunakan). Saya benar-benar menyiasatinya dengan menetapkan batasan yang ingin dipecah menjadi prioritas rendah, yang (dan ini merupakan asumsi) memungkinkan sistem untuk memecahkan kendala dengan anggun. Ini mungkin bukan solusi terbaik, tapi itu menyelesaikan masalah saya dan kendala yang dihasilkan bekerja dengan sempurna.

Nick Molyneux
sumber
2
Biasanya itu adalah situasi di mana Anda ingin menggunakan batasan placeholder yang dihapus saat runtime. Untuk menjadikan kendala sebagai batasan placeholder, buka inspektur kendala dan klik "Hapus saat membangun". Perhatikan bagaimana simbol balok-I kendala di area gambar IB berubah dari biru menjadi abu-abu untuk menunjukkan ini.
spencery2
1
Saya memiliki masalah yang sama. ketika saya menghapus batasan yang rusak desain saya rusak. Jadi saya mengatur prioritas ke medium.
Jeremy Piednoel