On a Project i use Objective-c 2.0-Swift2.0 and XCode 7.0.
So the matter is:
I'm tryin to put some string gotten from txt file in order to be shown into a UiTextView object.
The catch from another Object-C call was fine.
The reading of the file txt Was fine
...but the putting String into the UITextView! returns me always Nil. It's a dummy work but... it's still not work!
I tried to do the same as single Application Swift File: it works!
p.s. Notice i did a IBoutlet to connect the UIView Object into the StoryBoard to this Class.
Here's the code, if you need more details i would be happy to provide this.
import UIKit
#objc(TextControllerSwift) class TextControllerSwift: UIViewController {
var textRoom: String?
var textPlaying: String?
#IBOutlet weak var textMuseum: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
realplay()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func playText(textSelect: String) {
//textSelect REturn a string value from another Object-C Class -See comments in the Segue add in.
textPlaying = textSelect
}
func realPlay(){
let path = NSBundle.mainBundle().pathForResource(textPlaying, ofType:"txt")
if (path != nil){
//read the file
do {
let textRoom = try NSString(contentsOfFile: path!, encoding: NSUTF8StringEncoding)
print(textRoom)
}
catch {/* let's ignore when i didn't find file */}
textMuseum!.text="pippo" //Nil
print(textMuseum!.text) //Nil
textMuseum.text=textMuseum.text.stringByAppendingString(String(textRoom)) //Nil
}
}}
it give me
"fatal error: unexpectedly found nil while unwrapping an Optional value"
Why? Why? in the same project i call another Swift Class and it works really fine. (AKA i followed the guideline for coexisting Swift&Objective-C classes)
Thanks a lot in advance for your answers.
EDIT: Added info about the Caller from Objective-C, maybe this helps.
`if ([segue.identifier isEqualToString:#"segueIntroTesto"]) {
NSLog(#"%# in segueIntroTesto" , selectedIntroFilm);
TextControllerSwift *destViewController = segue.destinationViewController;
[destViewController playText:selectedIntroFilm];
}`
EDIT2:: removed *self.viewDidLoad()* under playText func.
EDIT3:: splitted the function playText() into another Function to give time to XCode (uffff) to get the new View then i REMOVED the old damned Outlet :D ...cheers I solved Thanks
Your problem is that you're trying to set the value of an outlet before the view gets loaded. Preparing for a segue happens before outlets are filled in.
Pass selectedIntroFilm into the controller and save it as a property during the segue, then call playText later...during viewDidLoad or viewWillAppear or whatever makes sense for the app.
Related
I am very new to iOS application programming (started learning just under a week ago!) so I'm sure what I'm asking is very obvious!
So I am working on an Application for my work study position and cannot for the life of me figure out what I'm doing wrong. Basically, all I want to do is check to make sure each field is filled in before allowing the user to carry on. I did a similar thing in another view controller to check to see if what was entered is equal to the password I set for the program (I am sure there is a better way to do this, but because I'm self learning and it's my first application, I'm not worried too much. I have a whole year to polish it!)
Here is the code for that (if you have suggestions that may improve it, feel free, but for the most part, I'm just trying to figure out why this worked and the other code is not)
#IBAction func enterPassword(_ sender: Any) {
pw = password.text!
let message = "Incorrect Password"
if(pw == "RISE")
{
performSegue(withIdentifier: "ToMenu", sender: self)
}
else {
incorrect.text = message
}
}
please note that the variable "pw" is a global variable and is declared outside of the class. Password and incorrect are both labels previously declared as well.
Here is the code that is in question. I do not understand why I am getting an error for this. it is "thread 1: exc_bad_instruction". I'm honestly not even sure what this error means so if you happen to know what it means, please enlighten me! I included all the code for the viewController with the issue.
import UIKit
var studName = " "
class CreateViewController: UIViewController {
#IBOutlet weak var name: UITextField!
#IBOutlet weak var ID: UITextField!
#IBOutlet weak var YR: UITextField!
#IBOutlet weak var test: UILabel!
#IBAction func endCreate(_ sender: Any) {
studName = name.text!
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
What am I doing wrong here? I am really uncertain and confused. I am pretty good at coding in Java and C++ so I never expected to have issues learning but it's totally different and is taking a lot longer than I expected (It took me about a week to learn C#...).
Thanks for any help!
EDIT:
(I need 10 reputation to post more than two links, so I deleted the error. lol I guess I'll go answer some questions or something)
Click here to see StoryBoard
Click here to see Connection to NAME (note I reconnected it and used all caps, error is still an issue)
if there is any other information that may help you understand, please let me know! Thanks!
I'm assuming here that you are experiencing the crash on this line
studName = name.text!
? (If not could you please include the stack trace to indicate where you are getting an issue?)
It looks like either name is nil, or text is nil both of which are being force unwrapped here. So either you haven't connected this text field properly in interface builder, or there is just no text in it.
My general rule is (and I'm sure people will disagree with this):
NEVER use !
Such a simple rule :)
I reason this that, force unwrapping an optional variable is never (very, very rarely) required, and implies an assumption of a value that was clearly intended to be allowed to be nil (otherwise it would not be optional). Typically, if you find yourself using a ! on one of your own variables, consider refactoring the variable to not be optional, otherwise make heavy use of optional binding and/or guard statements to avoid forcing things.
(My one main caveat for this is creating instance variables that require self as a parameter for initialisation. Where the instance variable is an implicitly unwrapped optional, but is set immediately after the call to super's initialiser, and never again)
Also, while it works and is valid code, it is not typical to use global variables for things like studName, this should be an instance variable in your controller.
Do feel free to shout if you have any other questions about this (or anything iOS/swift). If you're just getting started, I can't recommend http://web.stanford.edu/class/cs193p highly enough! A thorough rundown of all core iOS technologies and design patterns.
EDIT for comment
In this case you could avoid using this ! by making your variable optional, you could declare studName using
var studName: String? = " "
this makes it an optional variable which will allow you to assign a nil value to it.
If you are sure you don't want it to be nil, you could also do your assignment as
studName = name.text ?? " "
This will check the value of name.text and if it is not nil assign to studName, otherwise it will assign the value on the right " ". It essentially allows you to provide an default value for an assignment that is not optional. It is shorthand for:
if let text = name.text {
studName = text
} else {
studName = " "
}
Great start. Here is how I would write it:
#IBAction func enterPassword(_ sender: Any) {
//Make sure we trim off any white space or new lines and then optionally bind the text in the text field.
guard let passwordText = self.password.text?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) else {
self.incorrect.text = "Please enter a password."
return
}
//Make sure text is not a blank string eg: ""
guard !passwordText.isEmpty else {
self.incorrect.text = "Please enter a password."
return
}
//Make sure it is the password we want.
guard passwordText == "ThePassword" else {
self.incorrect.text = "Not the correct password."
return
}
//Success! Do other stuff here. Like perform a segue.
}
And just for good measure and a little fun. Here is a great extension on UITextField to provide a nice little shake animation if anything is invalid.
extension UITextField {
func shake(times T: Int, distance D: CGFloat) {
UIView.animate(withDuration: 0.06, animations: {
self.transform = CGAffineTransform(translationX: D, y: 0)
}) { (didComplete) in
UIView.animate(withDuration: 0.06, animations: {
self.transform = CGAffineTransform.identity
}, completion: { (didComplete) in
guard T > 0 else {
return
}
self.shake(times: T - 1, distance: D)
})
}
}
}
George Green is right. Force unwrapping in Swift is considered a code smell. Always optionally bind an optional value. Makes for a little more verbose code but keeps everything safe.
There you go... here I See the problem. I removed Outlet to the TextField and immediately I saw that error.
Please make sure you connect the IBOutlet properly and it works perfectly as shown below.
Hope this helps you.
Firstly,
Take an Outlet for the TextField as shown below
// MARK:- IBOutlets
#IBOutlet var passwordTextField: UITextField!`
Take a Button & assign IBAction for the the button, "passwordCheck" in this case.
You can compare TextField text to string as shown below
// MARK:- IBActions
#IBAction func passwordCheck(_ sender: Any) {
if passwordTextField.text == "RISE" {
print("perform Segue")
} else {
print("Do nothing")
}
}
Let me know if you have any doubts...
This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 6 years ago.
I am new to swift, I am writing an app which needs to change images in the storyboard. i have written a function to change images in the image view. In the function there is an if condition the image should be changed when the if condition is satisfied, but i got "unexpectedly found nil while unwrapping optional value" error when if condition is executed.
import UIKit
import MessageUI
import Foundation
import CoreLocation
class ViewController: UIViewController {
#IBOutlet var F_IMG: UIImageView!
#IBOutlet var FL_IMG: UIImageView!
#IBOutlet var FR_IMG: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
TimeService.initial(viewcontroller: self)
}
public func showImages(){
var type: String = Otherclass.gettype()
setImageForType(type:type)
}
public func setImageForType(type:String){
if (type == "NONE"){
DispatchQueue.main.async {
self.F_IMG.image = UIImage(named: "r_f")
}
"The showImage() function is called in another class."
I have the image in the bundle, but my UI is not getting updated and it always shows the error "unexpectedly found nil while unwrapping optional value"
Make sure FrontImg is properly connected to Storyboard or correctly initialised through code.
Update:
As it turns out, you're calling showImages() from other class, hence it is giving nil error.
By calling ViewController.showImages() from other class, you are creating a new ViewController, not referencing an existing one. This new one doesn't have a F_IMG(imageView) yet because its view hasn't been built. You reference self.F_IMG.image is nil.
My advice is to use NSNotificationCenter for updating UI in other View Controller.
For more approaches, refer this SO Answer
I believe the problem was caused in this line :
self.FrontImg.image = UIImage(named: "r_f")
If you check the Apple Docs on UIImage class, the initializer you are using init?(named name: String) actually returns optional.
So, have you tried
self.FrontImg.image = UIImage(named: "r_f")!
The only thing here which I have found to make sure your UIElement FrontImg must be connected properly.
I have a project with various class files. I have a barcode scanner which I have used from an online source which outputs the values in an alert controller. What I would like to do is take the barcode value and pass it back to a my main class and using a function parse it and display it in the relevant labels. For some reason I cannot get it to do this if anybody has any ideas that would be great. I have spent all day trying to figure this out without any luck.
barcodeScanner class relevant section
/* AVCaptureMetadataOutputObjectsDelegate */
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
if alertController != nil {
return
}
if metadataObjects != nil && metadataObjects.count > 0 {
if let machineReadableCode = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
// get the barcode string
let type = machineReadableCode.type
let barcode = machineReadableCode.stringValue
I need to get the barcode let value above to the passengerInformation class where it will be passed through submitCodeAuto function to write the labels.
passengerInformation().self.submitCodeAuto(barcode)
My crack at it above which doesn't seem to work..
// display the barcode in an alert
let title = "Barcode"
let message = "Type: \(type)\nBarcode: \(barcode)"
displayAlert(title, message: message)
}
}
}
}
passengerInformation class
#IBOutlet weak var firstNameResponse: UILabel!
#IBOutlet weak var lastNameResponse: UILabel!
#IBAction func submitCodeAuto(sender: AnyObject!) {
firstNameResponse.text = barcodeProtocol(barcode).firstName
lastNameResponse.text = barcodeProtocol(barcode).lastName
}
Above the submitCodeAuto function also sends the incoming barcode through another function called barcodeProtocol which formats it allowing for first and last name to be retrieved.
I have currently tested the labels with a button running a textfield value through barcodeProtocol and displaying in the labels so that all is working.
I have also hooked up a button to a new viewcontroller with the scanner class that works fine. Showing the camera scanning and displaying the value.
but I just haven't been able to join them up. The app is returning fatal error: unexpectedly found nil while unwrapping an Optional value
Any help would be great thanks.
In your function:
#IBAction func submitCodeAuto(sender: AnyObject!) {
firstNameResponse.text = barcodeProtocol(barcode).firstName
lastNameResponse.text = barcodeProtocol(barcode).lastName
}
where did you get 'barcode' from?
Try replacing it with
#IBAction func submitCodeAuto(sender: AnyObject!) {
firstNameResponse.text = barcodeProtocol(sender as! String).firstName
lastNameResponse.text = barcodeProtocol(sender as! String).lastName
}
I am assuming that your method barcodeProtocol takes in any string and perfectly parses it into firstname and lastname
Your code is riddled with problems.
You create a new instance of your passengerInformation class from your barcodeScanner code, invoke the submitCodeAuto() method, and then forget about the newly created passengerInformation object. (presumably it's a view controller.)
It does not make sense to create a new view controller, send it a message, and then forget about it. That won't do anything. You probably want to instantiate your custom passengerInformation view controller from a storyboard, set a barcode string property in the view controller, and then present it modally using presentViewController:animated:completion:. In your passengerInformation view controller's viewWillAppear method, you should take the barcode property, extract the info you need from it, and install it into your text fields.
Your submitCodeAuto() method is declared as an IBAction even though you're not using it that way. It takes a parameter sender which you ignore, and instead you use a variable barcode which you don't show.
Your submitCodeAuto() function should probably take a parameter barcode of type String, since that's what it seems to be doing.
You have several classes who's class names start with lower-case letters. Class names should start with upper-case letters.
I have a custom UITableViewCell class named PinCell.swift which contains a reference to a UITableViewController and an IBAction that passes data from the cell to the UITableViewController. I have no errors and everything builds fine.
PinCell.swift (UITableViewCell):
var viewControllerB:UITableViewController!
#IBAction func titleButtonPressed(sender: AnyObject) {
var venueIDFromRequest = self.pin?["venue"]["id"].stringValue
println("venueIDFromRequest is: \(venueIDFromRequest)")
if venueIDFromRequest != nil {
let venueDetailRef = viewControllerB as! VenueDetailViewController
venueDetailRef.venueIDPassed = venueIDFromRequest!
}
if(self.delegate != nil){ //Just to be safe.
self.delegate.callSegueFromCell(venueIDFromRequest: venueIDFromRequest!)
}
}
VenueDetailViewController.swift (UITableViewController)
var venueIDPassed:String! = "asdklasdkas"
When I tap the button in my app, it crashes and the following is printed out to the console fatal error: unexpectedly found nil while unwrapping an Optional value which we have all seen before and I realize what this error means. My question is why is this happening when it seems to have a reference to the variable in the other view controller? Even when I println(venueIDFromRequest) I get the correct data. What am I doing wrong here and how can I assign venueIDFromRequest to self.viewControllerB.venueIDPassed ?
Here is a screenshot if it can help diagnose what is actually going on:
I am new to Swift/iOS, so please bear with me:
I am trying to access a function in one class from another class, and update an UIImage name.
Within my viewcontroller class I have
class Documents: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var UpdateImage: UIImageView
override func viewDidLoad() {
super.viewDidLoad()
UpdateImage()
}
func UpdateImage() {
UpdateImage.image = UIImage(named: "NewImage")
}
}
Everything works, the Image gets updated to "NewImage"
Question: I can access the UpdateImage func from another class, but why is it generating an error when trying to change the image in the Documents class?
class GetChanges {
var success = { operation:AFHTTPRequestOperation!, response:AnyObject!) -> Void in
var MakeChange = Documents()
MakeChange.UpdateImage()
}
}
This generates an error on the "UpdateImage.image = UIImage(named: "NewImage")" in the Documents Class; "fatal error: unexpectedly found nil while unwrapping an Optional value"
When you call it within the class itself, it is operating on itself and it has already been created from a nib/storyboard. This means that UpdateImage exists.
When you call the method from another class, when you call this line:
var MakeChange = Documents()
You are creating a new instance of Documents. This is not initialized through the nib/storyboard, and thus it never populated the IBOutlet value UpdateImage. Because this value doesn't exist, it unexpectedly finds nil and throws an error.
You need to somehow retain a reference to the instance of Documents you're trying to display. I'd need more information to tell you how to do that.
Also, because you mentioned that you're new, I'd like to point out a few issues I notice with your code that is making it very difficult to read.
Capitalized names are reserved for Types variable names should (almost) never begin with a capital letter.
Variable names should reflect the object they represent. UpdateImage sounds like it is an image. It would be better to name this updateImageView
Functions should be lowercase as well. It is strange to see capitalization this way and makes the code a bit uncomfortable to read.
Good luck!
Read about View Contoller's lifecycle, it's very important knowledge for iOS developer.
As Logan said:
You are creating a new instance of Documents. This is not initialized through the nib/storyboard, and thus it never populated the IBOutlet value UpdateImage
This means that after call init for ViewController (i.e. Documents()) nib isn't loaded. You can use outlets of viewController in another code only after viewDidLoad stage. Apple docs:
The nib file you specify is not loaded right away. It is loaded the first time the view controller's view is accessed. If you want to perform additional initialization after the nib file is loaded, override the viewDidLoad() method and perform your tasks there.
You can remove MakeChange.UpdateImage(), because it will be called in viewDidLoad. Or, if you want pass specific image name to view controller:
class Documents: UIViewController, UITableViewDataSource,
UITableViewDelegate {
#IBOutlet var UpdateImage: UIImageView
var imageName: String?
override func viewDidLoad() {
super.viewDidLoad()
updateImageView()
}
func updateImageView() {
if let imageName = imageName {
UpdateImage.image = UIImage(named: imageName)
}
}
}
After that, you can use
let documentsViewController = Documents
documentsViewController.imageName = "newImage"
When you load documentsViewController, newImage will be presented