TL;DR: I have an IBOutlet (UILabel) that is properly connected in Storyboard. Accessing (unwrapping) it works fine in viewDidLoad() ... but a few seconds later its value is nil. A watchpoint says that the outlet changes right after a call to viewDidLayoutSubviews(), but... a print() call at the end of viewDidLayoutSubviews() shows it non-nil.
This is very similar to IBOutlet is nil but his solution (track value with didSet()) did not work. (There are many related posts but all had trivial solutions.)
What I have done:
Reconnected the outlet to the Label — from both sides
Deleted the Label and reconnected it
Cleaned the project
Deleted the DerivedData
Quit and restarted Xcode
Quit and restarted my Mac
Added a didSet() method to the outlet.
It triggers during viewDidLoad() and shows a non-nil value.
In viewDidLoad() I set its text value with no problem
It does not trigger before the nil-unwrapping crash
Added a watchpoint to the variable.
This does trigger before crash (right after viewDidLayoutSubviews() and shows the following:
As mentioned before, at exit of the most recent method call before the watchpoint (viewDidLayoutSubviews()) the outlet is non-nil.
These crashes seem always to involve subviews of a particular superview. I added a watchpoint to the superview's outlet but it never triggers.
What could be inciting my code to let go of this weak reference?
TL;DR: I was clobbering the relevant views.
Well, the best way to find your own answer is to ask someone else. Thanks to #DonMag, I was preparing more traces, breakpoints, and screen shots. I noticed this method (added to fix another bug, of course):
Of course, the two views that were becoming nil were subviews of centralOverlay. Ones I wanted to keep.
So I guess my answer was similar to that of IBOutlet is nil — pilot error — except the didSet() handler did not solve the mystery.
Related
In the screen shots below, the only change I have made is to connect an IBOutlet for a constraint. Unconnected, screen lays out correctly. Connected, the screen lays out incorrectly. I have not seen this happen before and don't know what to try to fix it. I need to be able to modify the constant value of the constraint in order to resize a subview depending on the presence or absence of a particular item.
The IBOutlet is declared as:
#IBOutlet weak var tabContentBottomConstraint: NSLayoutConstraint!
So far, I have not implemented any code that reads or modifies this constraint. I added it to my view controller in preparation for using it, but have not gone any further because when I run the code after adding the IBOutlet, the view sizes incorrectly. I have added and removed several times, always with the same result.
Here is the debugger info on the view sizings prior to connecting the outlet:
And here is the debugger info after connecting the IBOutlet with no other code change whatsoever:
The difference in y offset is huge and pushes the view off the screen. As I said above, no code reads or writes to that IBOutlet.
The rolePageDrawerView is item2 in the constraint, and item1 is the view controller's view.safeAreaLayoutGuide. rolePageDrawerView is embedded 3 levels deep into child views of view.safeAreaLayoutGuide.
I found a way to work around this weird behavior by programmatically searching out the constraint with the following code:
guard let tabContentBottomConstraint = view.constraints.filter({ $0.secondItem! as! NSObject == rolePageTabContentView }).first else {
fatalError("unable to find the constraint for drawer sizing")
}
self.tabContentBottomConstraint = tabContentBottomConstraint
I left the constraint as a weak reference even though it is no longer injected since the view itself will have a reference to it to keep it alive. It works.
HOWEVER, I'm leaving the question open for a better solution. The above search is very fragile some the layout change in the future. It would be much better if the framework was injecting the constraint without breaking the layout. Still open for better solutions.
I have a simple UILabel, nothing special about it, in a UIView inside a UIScrollView. I can link it up to my ViewController.swift file just fine, and it doesn't crash on opening, but whenever I try to use the outlet, it produces a nil. I've been looking around for a solution and it seems as though you can't access an outlet inside a subview from the superview... but nothing has been exactly my situation, and none of the provided solutions work.
Here is the full error: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
The strange thing, though, is that I have another UILabel, seemingly the exact same, that works fine when I try to edit it. I do not know what is going on in the slightest here. How can I fix this?
"right click" no your label in storyboard and check if you don't have another outlet connected, maybe you deleted from code and connection is still there, other than that, you can delete the label from storyboard and recreate connections.
Try providing the #IBOutlet as not weak and try.
This is not the right way, but still let us see if it's working.
I am relatively new to iOS development with Swift (I actually have 3 years of experience with Android development with Java, trying to learn a new technology). I am creating an app that requires the usage of a library known as SearchTextField:
https://github.com/apasccon/SearchTextField
In a shellnut, it's a UITextField subclass that has a dropdown suggestions/autocomplete functionality.
Below is the ViewController that uses it...
#IBOutlet var homeAddressTextField: SearchTextField!
#IBOutlet var workAddressTextField: SearchTextField!
override func viewDidLoad() {
super.viewDidLoad()
homeAddressTextField.delegate = self
workAddressTextField.delegate = self
homeAddressTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
workAddressTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
//vvvvvvvvv EXC_BAD_ACCESS CODE 2 THROWN BELOW vvvvvvvv
homeAddressTextField.filterStrings(["foo","bar"])
}
homeAddressTextField should be instantiated, otherwise any reference to it above should throw the same exception. When breakpointing into the problematic line, homeAddressTextField is NOT nil, and correctly shows that it is an instance of SearchTextField.
I have tried many things to fix or at least find the source of the error. As you can tell, I used a strong var instead of weak var for the Outlet.
I have tried using zombies to track any attempt to access a deallocated memory block, yet the zombie Instruments came up with no zombies accessed.
If it is worth noting, the error disappears as soon as the problematic line containing filterStrings() is removed. Any help is appreciated!
It seems bug in library, could you please check here
SearchTextField Issue
It is in still open issues at their repository.
Kindly watch issues in repository, if you try to use someone readymade code.
Are you sure you've attached your IBOutlet in interface builder?
Try putting a breakpoint on the line that's crashing. That will stop it right before executing that line. Then, in the console (command+shift+y) you'll see a line that says "lldb" - put your cursor there and type po homeAddressTextField and see if it returns a value, or nil. If nil, then the IBOutlet is not set properly, which would cause bad access.
Additionally, if it is indeed nil, you'll want to make sure that the subclass and module are both set within interface builder on the SearchTextField, as well as making sure to set the outlet itself. You can also try filtering these strings in the viewDidAppear() method just to see if it is indeed an issue with the reference to the SearchTextField.
Edit: I've looked through the code a bit of the repo. You might not want to set the datasource and delegate properties, as the SearchTextField has a datasource and delegate of its own. You simply need to set the filterable strings as you are on the last line. So try removing the calls to make the view controller the datasource/delegate.
Clicking the textField and then adding class name = SearchTextField.swift worked for me.
I'm having a problem with setText method for UITextView.
As I said on the title, I tried to change a UITextView text by using setText method or change the text property directly. It only works from the second time since the method is called.
My UITextView was an outlet. I even tried to change it's text directly from the owner class or create a method to call from another class, but it behaves the same.
I dont know if I'm doing sth wrong when create it as an outlet, I also tried to set it as nonatomic, strong, weak, retain but I still can't get it.
Any advice for my case? Thanks in advance! :)
EDIT:
I figured it out from David H's answer.
As my app is using tab, first tab is used for searching words, the second one for displaying the meaning, I tried to set the text before the outlet is created (as I haven't clicked the second tab yet). If I click the tab meaning first in order to let the outlet to be created, then it works perfectly.
Thanks for all the answer!
Almost for sure, the first time you try to set it the outlet is nil - not yet set. So add an assert (assert(myTextView) before you set it, or at least a NSLog message. You will surely find that the textView is nil the first time you try.
When creating UIs in IB I have often used buttons that have an action but there is no reason for the view controller to access this button.
The button text never changes, the button image never changes, it never moves, etc...
Because of this I don't give it an IBOutlet property and I don't connect it up to anything in the VC (other than the action of course).
There is a similar question on SO that I've read and the arguments on there go into memory management issues. That question is from early 2011, before ARC. Given that all my IBOutlet properties are weak anyway the memory is dealt with by their superview not by the view controller. So the issues mentioned in that question are now moot.
Is there a reason to connect them up now? Should they always have a connection? If so, why?
Short answer: no.
IBOutlets are needed to refer to elements of the UI.
If you don't need to access to such elements, you don't have to connect them with a IBOutlet
Answer is NO.
But here's a valuable tip, if someone sees this question/answer and goes gung ho and deletes all the unused IBOutlets.
If you remove an IBOutlet for a UIElement, make sure that the UIElement in the IB is not referencing to the now non-existant outlet. Otherwise, you'll have some weird crashes, that'll take quite some time to be resolved.
This is an issue that has had me in a soup many times. I am not sure if this has been fixed in the latest versions of Xcode, but its safer to check.