Swift bad execution when checking length - swift

I am trying to evaluate the contents of a form field that, when empty is throwing an error.
Here is the outlet code
#IBOutlet var txtUsername : UITextField!
Here is the println for the target field.
println("\(txtUsername)")
<UITextField: 0x10e8280a0; frame = (20 40; 280 30); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x10e828b20>; layer = <CALayer: 0x10e828300>>
So, looking at this I would assume that txtUsername.text is empty or == "". But everything I try to do to evaluate this throws an error.
if countElements(txtUsername.text as String) != 0 {
... code here
}
if txtUsername.text.bridgeToObjectiveC().length != 0 {
... code here
}
if txtUsername.text.utf16count != 0 {
... code here
}
if txtUsername.text != "" {
... code here
}
All bring back "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Also, evaluating whether it is nil doesn't seem to work. The below scripts show that there is something to be evaluated, even though it is blank. The problem is telling whether or not it is blank.
If the field was nil, I would expect it to return false and trigger the else statement.
if let evalText = txtUsername.text{
println("There is something here : \(evalText)")
} else {
println("text is nil")
}
// This returns "There is something here:"
if txtUsername.text{
println("There is something here")
} else {
println("text is nil")
}
// This returns "There is something here"
I have even tried to set the value in a variable, only to have it kick out the error after hitting the "if" statement.
Thanks,

EXC_BAD_INSTRUCTION implies an assertion failure. This is most common when something is nil but you are still trying to operate on it.
The text property of UITextField is an Implicitly Unwrapped Optional (String!). You must first check if it is nil. Your app is crashing because it is nil.

txtUsername.text is an optional in Swift. Even your label is an optional so it's not really safe to use ! when declaring it. But anyway, try using this:
if let currentText = txtUsername.text {
// ... Do something with currentText ...
}
else {
NSLog("Text is nil")
}
To be extra sure you can even check if txtUsername is set in the same way. So in the end you will have this:
if let currentTxtUsername = txtUsername{
if let currentText = currentTxtUsername.text {
// ... Do something with currentText ...
}
else {
NSLog("Text is nil")
}
}
else {
NSLog("Text label is nil")
}
Don't forget to remove the ! in the declaration part though.

Turned out to be an error ghosting issue.
The actual problem was that it would get further down in the code and run into a situation where I was inadvertently trying to put nil data from a core data object back into the text string. Setting a text field to nil doesn't work, but rather than error where the problem was, it erred at the "if" statement 20 lines above it.
Below is the full code, and some description of the issue.
#IBAction func btnLoad(sender : AnyObject) {
var appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
var context = appDel.managedObjectContext
var request = NSFetchRequest(entityName: "Users")
request.returnsObjectsAsFaults = false
// Here is the place where it throws the error.
if txtUsername.text == "" {
request.predicate = NSPredicate(format: "username = %#", "\(txtUsername.text)")
}
var results = context.executeFetchRequest(request, error: nil)
println(results)
if(results.count > 0){
var res = results[0] as NSManagedObject
println("\(res)")
//*** The database had nil values for the result selected. And nil doesn't go into a text field.
txtUsername.text = res.valueForKey("username") as String
txtPassword.text = res.valueForKey("password") as String
responseLabel("User Found")
} else {
responseLabel("No Users Found")
}
}
Thanks everyone for replying.

Related

Vision image process returns nil ML Kit Firebase

I am trying to build a text recognizer app in iOS with the Firebase ML Kit. I have tried following some tutorials, but no luck. I keep getting the following error at the line indicated (return self.result):
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
I am still very new to Swift/xcode and firebase so any help would be greatly appreciated!
var result: VisionText!
var textRecognizer: VisionTextRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let vision = Vision.vision()
textRecognizer = vision.cloudTextRecognizer()
imageResult.image = UIImage(named: "sampletext")
print(textRecognition(image: imageResult.image!))
textResult.text += scantext
}
func textRecognition(image: UIImage) -> VisionText{
let visionImage = VisionImage(image: image)
textRecognizer.process(visionImage) { (result, error) in guard error == nil, case self.result = result else {
print("oops")
return
}
print("oops")
}
return self.result \\ ERROR
}
EDIT
I made sure to implement a correct way to unwrap an optional. My problem is that the Firebase MLVision process does not return anything, the result is nil. Not sure if I am going about the method incorrectly. Here is my updated code with some small changes.
var scannedresult: VisionText!
var textRecognizer: VisionTextRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let vision = Vision.vision()
textRecognizer = vision.cloudTextRecognizer()
imageResult.image = UIImage(named: "sampletext")
print("oops")
print(textRecognition(image: imageResult.image!))
// textResult.text += scannedresult.text
}
func textRecognition(image: UIImage) {
let visionImage = VisionImage(image: image)
textRecognizer.process(visionImage) { (result, error) in guard error == nil, let result = result else { print("oops")
return }
self.scannedresult = result
}
}
"Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value"
^This error occurs when you are trying to access a value for an option variable, and the value is nil. You have to unwrap it safely. There are five ways to unwrap an optional. This is my preferred way:
guard let result = self.result else { return }
return result
the guard statement will cause your code to skip over the next lines in the block if there is no value, or NIL, in the result.
Here is a quick read on all the ways to unwwrap your optionals w/ examples

How do I check if userDefault is empty?

I'm trying to deny access to a certain view controller if the userDefault is empty, but the code doesn't seem to work. To be a bit more clear, I'm saving a favorite-list to a userDefault. This is my code:
if UserDefaults.standard.array(forKey: "favorites") == nil {
navigationController?.popToRootViewController(animated: true)
return
}
The error is Index out of range, which means that the whole block is ignored (the code after this block runs and since the user default is empty it crashes when trying to retrieve information that isn't there).
The funny thing is, the code works the first time I try to enter the viewController (it denies me access). But if I favorite mark an object (save to userDefault), then un-favorite the same object (userDefault becomes empty), and enter the viewController, the program crashes.
I have tried:
if let favExist = UserDefaults.standard.array(forKey: "favorites") {
print("")
print("FAV EXISTS")
print("")
}else {
print("")
print("NOPE")
print("")
navigationController?.popToRootViewController(animated: true)
return
}
...and the same problem persists. In print() the log tells me FAV EXISTS after I favorite mark, then un-favorite mark, then try accessing the page (even though the userDefault now should be empty).
I have also tried code from other threads. The suggested code to solve my problem from the other thread was:
let defaults = UserDefaults.standard
if (!defaults.bool(forKey: "favorites")) {
defaults.set(true, forKey: "favorites")
}
I'm not really sure how to implement it though? Where do I use this? And what does it do?
Any idea what's wrong?
It´s enough to do this:
if let favorites = UserDefaults.standard.array(forKey: "favorites") {
// userDefault has a value
} else {
// userDefault is nil (empty)
}
Update:
You need to make a check within the if-statement if your arrat has any values too:
if let favorites = UserDefaults.standard.array(forKey: "favorites") {
print("Favorites exists")
if favorites.isEmpty {
print("Favorites is empty")
} else {
print("Favorites is not empty, it has \(favorites.count) items")
}
} else {
print("Favorites is nil")
}
When you set the UserDefaults Array also set a BOOL to UserDefaults. When you recover the Bool it won't crash even if it hasn't been set.
var favouritesset = UserDefaults.standard.bool(forKey: "favoritesset")
if favouritesset == true {
//Then Recover the Array
var array = UserDefaults.standard.array(forKey: "favorites")
}
OK, Rashwan L solved it for me. Thing was, my code (and suggested code by others) checked whether or not userDefault existed or not - it didn't bother whether there was a value stored or not. To work around the problem, I had to test if favExist.count == 0 was true. If true, user is blocked from the page and prevented from accessing the rest of the code. Se below:
if let favExist = UserDefaults.standard.array(forKey: "favorites") {
if(favExist.count == 0)
{
navigationController?.popToRootViewController(animated: true)
return
}
}else {
navigationController?.popToRootViewController(animated: true)
return
}
You do like this:
if UserDefaults.standard.array(forKey: "favs") != nil {
// userDefault has a value
} else {
// userDefault is nil (empty)
}

How do I validate IBOutlet/var for nil?

I've written a simple application using Swift and Xcode 6.1.1. The program, which is a simple calculator, works well but I haven't been able to validate non-nil input for the three text fields. As a result, if the user leaves the field blank and then hits "calculate," the application crashes.
The app takes three inputs, initially as strings. I wrote an if statement to check for nil but it doesn't work - it will just pass to else regardless. Here's the code block that's relevant to my question:
...
#IBOutlet var calcButton: UIBarButtonItem!
#IBOutlet var yearOneField: UITextField!
#IBOutlet var yearTwoField: UITextField!
#IBOutlet var yearThreeField: UITextField!
#IBOutlet var displayWindow: UILabel!
#IBAction func calcButtonTapped(sender: AnyObject) {
if (yearOneField == nil) {
displayWindow.text = ("Non-zero entries are not permitted. Please enter new values.")
} else {
let yearOne = yearOneField.text.toInt()
let yearTwo = yearTwoField.text.toInt()
let yearThree = yearThreeField.text.toInt()
...
I was thinking I could evaluate the IBOutlet for nil but that didn't work. I'm new to Swift and Xcode so I hope this is a n00b question to the more experienced developers out there. Thank you.
The only way the #IBOutlets could be nil is if you forgot to wire them up in Interface Builder. Usually you don't need to check that because the crash will tell you to fix that problem.
The toInt() function returns an Optional Int (aka Int?) that must be unwrapped before being used. toInt() will return nil if the value in the text field does not represent a valid Int. "2.1", "seven", and "" would all return nil if converted with toInt(). I recommend you use optional binding (if let) syntax to check the conversion for nil and unwrap the result if it is not nil:
if let yearOne = yearOneField.text.toInt() {
if let yearTwo = yearTwoField.text.toInt() {
if let yearThree = yearThreeField.text.toInt() {
// yearOne, yearTwo, and yearThree are all valid Ints
// so do the calculations
}
}
}
Alternatively, if you know you want to use a default value (like 0) when the field can't be converted to an Int, you can unwrap the result using the nil coalescing operator ?? like so:
let yearOne = yearOneField.text.toInt() ?? 0
let yearTwo = yearTwoField.text.toInt() ?? 0
let yearThree = yearThreeField.text.toInt() ?? 0
The text fields themselves will never be nil. They are created and assigned during initialization, and you're never removing them.
I think you want to check if their text properties contain any text, which you can do like this:
Updated for Swift 2:
if let text = yearOneField.text where !text.isEmpty {
// perform the conversions
} else {
// the text field is empty
}
You can avoid nesting using guard:
guard let text = yearOneField.text where !text.isEmpty else {
// the text field is empty
return
}
// perform the conversions
I prefer the guard syntax because it's clearer about what the ideal result is.
You can just check as you do with normal optionals.
guard let unwrapped = myLabel else {return}
Or like this
if myLabel == nil {
//do stuff
}
Or like this:
if let unwrappedLabel = myLabel {
}

UIImageView is NIL

I have a default image in viewItem to make sure that it is working, it shows on the detail view of the splitview.
#IBOutlet weak var ImageView: UIImageView!
var imageCache = [String: UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
self.configureView()
}
func configureView() {
if let detail: AnyObject = self.detailItem {
if let label = self.detailDescriptionLabel {
let dict = detail as [String: String]
label.text = ""
let s = dict["result"]
let vr = NString(string: s!)
let vrd = vr.doubleValue
let value = ceil(vrd*20)
let valueString = String(format: "%.0f", value)
vresult.text = "\(valueString)%"
getPic(dict) // <---- trouble maker
fitem.hidden = false
ritem.hidden = false
}
} else {
navigationController?.popViewControllerAnimated(true)
}
}
func getPic(item: [String: String]) {
var chachedImage = self.imageCache[item["image"]!]
println(item["image"]) // <-- prints out the url
if cachedImage == nil {
var imgUrl = NSURL(string: item["image"]!)
let request: NSURLRequest = NSURLRequest(URL: imgUrl!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {( reponse: NSURLResponse!, data: NSData!, error; NSError!) -> Void in
if error == nil {
cachedImage = UIImage(data: data)
println("got here no problem") // <-- prints out
self.imageCache[item["image"]!] = cachedImage
println(self.imageCache) // <-- prints reference OK
dispatch_async(dispatch_get_main_queue(), {
self.ImageView.image = cachedImage // <---- offender
})
} else {
println("Error: \(error.localizedDescription)")
}
})
} else {
dispatch_async(dispatch_get_main_queue(), {
self.ImageView.image = cachedImage
})
}
}
ImageView is coming up nil every time.
fatal error: unexpectedly found nil while unwrapping an Optional value
but the default image shows. I've moved this out of the dispatch and even tried setting it straight from the viewDidLoad() always errors. It used to be a UIWebView and worked perfectly except that it would not cache anything. Since loading these images is a lot of work, I thought caching would be good, I've got caching working for thumbnails in the MASTER view.
It may be because of how your instaciating your viewcontroller.
let vc = MyViewController()
Something like this wont work. You're creating the VC without actually giving the storyboard a chance to link the IBOutlets. Instead use
storyboard.instantiateViewControllerWithIdentifier(identifier: String)
You may need to get reference to the storyboard using
let storyboard = UIStoryboard(name: name, bundle: NSBundle.mainBundle())
Hope this helps :)
Changing your variable name shouldn't make any difference except for readibility/maintainability unless there's a namespace conflict (good to understand why/where that might be happening). Also I was wondering - you made the IBOutlet'ed varable weak. When the last remaining strong ref to the object goes away, the weak references to the object are set nil by the runtime/garbage collector automatically. (Look up that section of the Swift documentation if you're not solid about it).
Maybe you should check your classes and controllers by adding deinit { println(,"function name deallocated' }. Between your use of weak and improved behavior seen when you change the variable name, it seems like there might be some weird (buggy) interactions going on in your app itself.
Well silly me. I've been working on this for a few days, I got the great idea to try and change the name, and it worked. I tried changing it back and it broke, apparently you can't use ImageView as a variable!
In my case was because I was using a nib and didn't register it.
Once I did registered it, it worked
My case Was Different I used
awakeFromNib()
instead of
viewDidLoad()
.

Swift and Realm EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) when result is 0

I have a call in my code which looks innocuous enough:
let index = allFilms.indexOfObject(film)
It generally has no problems, but my application crashes at this line when the value of index will be 0, that is, when film is the first item in allFilms, with the error EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
This is a call to Realm, which internally uses the following Objective-C++ code to create the return value:
- (NSUInteger)indexOfObject:(RLMObject *)object
// [...]
size_t object_ndx = object->_row.get_index();
size_t result = _backingView.find_by_source_ndx(object_ndx);
if (result == tightdb::not_found) {
return NSNotFound;
}
return result;
}
Does anybody know what's happening here?
Just to make doubly clear, the index is not coming back as NSNotFound, it's coming back as 0.
[edit] I'm wondering if Swift is doing some clever stuff where it's aware of how I'm casting this value further down the method. Here's the full method where you can see I'm doing some casting between UInt and Int.
func pageWithOffset(offset:Int, fromFilmWithIdentifier identifier:NSInteger)->UIViewController?{
let allFilms = Film.objectsWithPredicate(FilmQueries.predicateForCurrentlyAvailable())
let predicate = NSPredicate(format: "id == \(currentFilmIdentifier)")
let film = Film.findById(currentFilmIdentifier)
var index = allFilms.indexOfObject(film)
if index == UInt(NSNotFound) { return nil }
let resultIndex = Int(index) + offset;
if index < 0 || index >= allFilms.count - 1{
return nil
}else{
let film = allFilms[UInt(resultIndex)] as Film
return pageForFilmWithIdentifier(film.id)
}
}
I think the problem comes from when indexOfObject returns NSNotFound. You should check for index == NSNotFound, and if it is, then do not access the array.
This certainly looks like a Realm bug, though I can't reproduce it. Could you create a failing unit test in Realm that reproduces the issue? This is my (failed) attempt, which you can use as a jumping off point:
func testStackOverflow27982054() {
let realm = realmWithTestPath()
realm.transactionWithBlock {
SwiftStringObject.createInRealm(realm, withObject: ["a"]); return
}
let allStrings = SwiftStringObject.objectsInRealm(realm, "stringCol == %#", "a")
let index = allStrings.indexOfObject(allStrings[0] as SwiftStringObject)
XCTAssertEqual(index, UInt(0))
}