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.
Related
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.
I'm just a beginner in Swift coding. My idea is quite simple which is an app with two buttons. When clicked, a textfield will change its text.
In the Main.StoryBoard, I add a textfield and two buttons.
In ViewController.swift file. I write as this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textfield: UITextField!
#IBOutlet weak var button: UIButton!
#IBOutlet weak var button2: UIButton!
#IBAction func action1(_ sender: UIButton) {
textfield.text="you just clicked on button1"
}
#IBAction func action2(_ sender: UIButton) {
textfield.text="you just clicked on button2"
}
}
It is supposed to be all right. However, an error appears which shows:
thread1:signal SIGABRT
in file AppDelegate.swift line:
class AppDelegate: UIResponder, UIApplicationDelegate
What is wrong with my code?
You get a SIGABRT error whenever you have a disconnected outlet. Click on your view controller in the storyboard and go to connections in the side panel (the arrow symbol). See if you have an extra outlet there, a duplicate, or an extra one that's not connected. If it's not that then maybe you haven't connected your outlets to your code correctly.
Just remember that SIGABRT happens when you are trying to call an outlet (button, view, textfield, etc) that isn't there.
For me it wasn't an outlet. I solved the problem by going to the error And reading what it said. (Also Noob..)
This was the error:
And The solution was here:
Just scroll up in the output and the error will be revealed.
To solve the problem, first clean the project and then rebuild.
To clean the project, go to MenuBar: Product -> Clean
Then to rebuild the project, just click the Run button as usual.
A common reason for this type of error is that you might have changed the name of your IBOutlet or IBAction you can simply check this by going to source code.
Click on the main.storyboard and then select open as
and then select source code
source code will open
and then check whether there is the name of the iboutlet or ibaction that you have changed , if there is then select the part and delete it and then again create iboutlet or ibaction.
This should resolve your problem
In my case I wasn't getting error just the crash in the AppDelegate and I had to uncheck the next option: OS_ACTIVITY_MODE then I could get the real crash reason in my .xib file
Hope this can help you too :)
I had the same problem. I made a button in the storyboard and connected it to the ViewController, and then later on deleted the button. So the connection was still there, but the button was not, and so I got the same error as you.
To Fix:
Go to the connection inspector (the arrow in the top right corner, in your storyboard), and delete any unused connections.
If you run into this in Xcode 10 you will have to clean before build. Or, switch to the legacy build system. File -> Workspace Settings... -> Build System: Legacy Build System.
This is a very common error and can happen for multiple reasons. The most common is when an IBOUTLET/IBACTION connected to a view controller in the storyboard is deleted from the swift file but not from the storyboard. If this is not the case, use the log in the bottom toolbar to find out what the error is and diagnose it. You can use breakpoints and debugging to aid you in finding the error.
To find out how to fix the error please use this article that I found on Google: https://rayaans.com/fixing-the-notorious-sigabrt-error-in-xcode
In my case there was no log whatsoever.
My mistake was to push a view controller in a navigation stack that was already part of the navigation stack.
Sometimes it also happens when the function need to be executed in main thread only, so you can fix it by assigning it to the main thread as follows :-
DispatchQueue.main.async{
your code here
}
For me, This error was because i had a prepare segue step that wasn't applicable to the segue that was being done.
long story:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let gosetup = segue.destination as! Update
gosetup.wherefrom = updatestring
}
This was being done to all segue when it was only for one. So i create a boolean and placed the gosetup inside it.
In my case, I was using RxSwift for performing search.
I had extensively kept using a shared instance of a particular class inside the onNext method, which probably made it inaccessible (Mutex).
Make sure that such instances are handled carefully only when absolutely necessary.
In my case, I made use of a couple of variables beforehand to safely (and sequentially) store the return values of the shared instance's methods, and reused them inside onNext block.
I had the same problem. In my case I just overwrote the file
GoogleService-Info.plist
on that path:
Platform\ios\YOUR_APP_NAME\Resources\Resources
In my case the files were present without data.
If this crash occurs when accessing a view controller within a package you may have to remove the Class and Storyboard ID from the view controller within the package and then add them again, run the project and the view controller should be found
I have created a custom subclass of UITextField, CustomTextView.
I created a
private var tapGesture = UITapGestureRecognizer()
in the customTextView class
In the initInView, I have the following code
tapGesture.addTarget(self, action: "tapTextField:")
self.addGestureRecognizer(tapGestureRecognizer)
CustomTextView implements UIGestureRecognizerDelgate
CustomTextView has a private func named tapTextField
Now when I use iOS simulator and click on the text field, the function tapTextField never gets called.
What am I missing here? I saw similar posts but none of them answer my question. I could not comment on those as I don't have reputation yet. So asking as a new question.
PS: Does this have to do with firstResponder being set? This is someone else's code I am working on, so I might have missed something. Let me know what I should look for
Related stack overflow questions:
Add UITapGestureRecognizer to UITextView without blocking textView touches
UITextview: Place focus on becomefirstresponder
I don't know swift, but try changing this "tapTextField:" to this "tapTextField" and make sure you don't have any arguments/parameters/whatever swift calls them in your "tapTextField" function.
Also, it looks like
self.addGestureRecognizer(tapGestureRecognizer) should be self.addGestureRecognizer(tapGesture)
You can try few things to debug the problem.
1> Make sure there is no mistake of tapTextField and tapTextField: i.e. you are adding selector with argument but you have implemented same method without any argument.
2> Make sure no any other transparent view obscuring your custom uitextfield.
3> print po yourTextFieldName in the xcode console to see whether actually your textfield has any gesture recognizer added in it or not.
Hope this helps
Update: with 2 downvote of this question, I'd like to make this question a little bit useful to others - since I don't have the choice to delete it. The mistake I made was cut and paste codes which has interface outlet. As I was completely new at that time, I was assuming that when I copy and paste, the outlet link will be copied and pasted as well. Obviously it doesn't work that way.
I was writing a single-viewed app. It has one UITextField and one MKMapView. I want to do something when Return key is hit, so I basically followed
How to hide keyboard in swift on pressing return key?
But it does not fit well with my other codes. Any idea why it isn't working and how to fix it?
Make sure you connect your UITextField from StoryBoard to your searchText IBOutlet by control-dragging from the StoryBoard to the the searchText variable.
You have your outlet set up as implicitly unwrapped. That's the correct thing to do, but when your code executes the outlet must not be nil or your code will crash.
You probabably have a broken outlet link. Set a breakpoint and examine the outlet.
You can change your code to use an "if let" expression to prevent crashes. Search in the Swift language reference IBook for "Optional binding" to learn about it.
Edit:
The code might look like this:
if let requiredSerachText = searchtext
{
requiredSearchText.delegate = self
}
Recently I wrote some code where I tried to refer to an outlet on a UIViewController I'd just instantiated with [storyboard instantiateViewControllerWithIdentifier] and modify the subview that the outlet pointed to before presenting the ViewController. It didn't work because the ViewController's view hadn't loaded its subviews yet, including the one that my outlet referred to, so the property just gave me a null pointer.
After (with some struggle) tracking down the cause of my issue in the debugger, I Googled around and learned, through answers like this one, that I can cause the view to load its subviews without being displayed by calling the myViewController.view getter. After that, I can access my outlet without any problems.
It's a clear hack, though, and Xcode - quite rightly - doesn't like it, and angrily protests with this warning:
Property access result unused - getters should not be used for side effects
Is there a non-hacky alternative way to do this that doesn't involved abusing the .view getter? Alternatively, are there canonical/idiomatic patterns for this scenario involving something like dynamically adding a handler to be called as soon as the subviews are loaded?
Or is the standard solution just to replace myViewController.view with [myViewController view] to shut up Xcode's warning, and then live with the hack?
On iOS 9 or newer, one can use:
viewController.loadViewIfNeeded()
Docs: https://developer.apple.com/reference/uikit/uiviewcontroller/1621446-loadviewifneeded
I agree that forcing a view to load should be avoided but I ran into a case where it seemed the only reasonable solution to a problem (popping a UINavigationController containing a UISearchController that had yet to be invoked causes a nasty console says warning).
What I did was use new iOS9 API loadViewIfNeeded and for pre-iOS9 used viewController.view.alpha = 1.0. Of course a good comment above this code will prevent you (or someone else) removing this code later thinking it is unneeded.
The fact that Apple is now providing this API signals it can be needed from time to time.
Not sure how much cleaner this way, but it still works fine:
_ = vc.view
UPD: for your convenience, you can declare extension like below:
extension UIViewController {
func preloadView() {
let _ = view
}
}
You can read explaination by following URL: https://www.natashatherobot.com/ios-testing-view-controllers-swift/
merged Rudolph/Swany answers for pre ios9 deployment targets
if #available(iOS 9.0, *) {
loadViewIfNeeded()
}
else {
// _ = self.view works but some Swift compiler genius could optimize what seems like a noop out
// hence this perversion from this recipe http://stackoverflow.com/questions/17279604/clean-way-to-force-view-to-load-subviews-early
view.alpha = 1
}
If I understand you correctly, I think there's another fairly standard solution: move the outlet modification/configuration code into a viewDidLoad method (of the recently instantiated VC).
The topic is also discussed in this question.
It would require some restructuring, but it might give you a "cleaner" design in terms of MVC if your incoming VC handled its own configuration, and it would avoid the "You should never call this method directly" stricture on loadView.
You can call [myViewController loadView] to explicitly load the view, instead of abusing the .view getter. The .view getter actually calls loadView if necessary when called.
It's still not a very nice solution, since the UIView Documentation's section on loadView explicitly instructs that
You should never call this method directly